Python __str__ і списки


107

У Java, якщо я зателефоную List.toString (), він автоматично зателефонує методу toString () на кожен об'єкт всередині Списку. Наприклад, якщо мій список містить об'єкти o1, o2 та o3, list.toString () виглядатиме приблизно так:

"[" + o1.toString() + ", " + o2.toString() + ", " + o3.toString() + "]"

Чи є спосіб отримати подібну поведінку в Python? Я реалізував у своєму класі метод __str __ (), але коли роздруковую список об'єктів, використовуючи:

print 'my list is %s'%(list)

це виглядає приблизно так:

[<__main__.cell instance at 0x2a955e95f0>, <__main__.cell instance at 0x2a955e9638>, <__main__.cell instance at 0x2a955e9680>]

як я можу змусити python автоматично викликати свій __str__ для кожного елемента всередині списку (або диктувати з цього приводу)?


Відповіді:


133

Виклик рядка зі списку python викликає __repr__метод для кожного елемента всередині. Для деяких предметів __str__і __repr__однакові. Якщо ви хочете такої поведінки, зробіть:

def __str__(self):
    ...
def __repr__(self):
    return self.__str__()

7
Ідентифікація __str__з, __repr__як правило, не узгоджується з моделлю даних Python , тому рішення щодо розуміння списку, запропоноване @ daniel-lew, є більш пітонічним.
Іоанніс Філіппідіс

2
Аргументу немає. Я відповів на запитання на запитання, яке часто є тим, як новачок python хоче думати про проблему, але це не означає, що це найкращий спосіб відповісти.
Девід Бергер

1
Python повинен відповідати власній моделі даних і робити те саме для всіх примітивів та агрегатів.
Терренс Браннон

2
Я думаю, що поведінка за замовчуванням для списків python очевидно неправильна. Я б очікував, що str()у списку повернеться str()кожен окремий елемент всередині.
SuperGeo

21

Ви можете використовувати розуміння списку для автоматичного створення нового списку з кожним елементом str () 'd:

print([str(item) for item in mylist])

6
Або просто print(map(str, mylist))- це крихітно трохи коротше
анула

4
Одна з проблем полягає в тому, якщо предмет у моєму списку також може бути списком
Breandán Dalton

7

Дві легкі речі, які ви можете зробити, використовувати mapфункцію або використовувати розуміння.

Але це дає вам список рядків, а не рядок. Таким чином, ви також повинні з'єднати рядки разом.

s= ",".join( map( str, myList ) )

або

s= ",".join( [ str(element) for element in myList ] )

Потім ви можете надрукувати цей складений рядковий об'єкт.

print 'my list is %s'%( s )

4

Залежно від того, для чого ви хочете використовувати цей вихід, можливо, __repr__це буде більш підходящим:

import unittest

class A(object):
    def __init__(self, val):
        self.val = val

    def __repr__(self):
        return repr(self.val)

class Test(unittest.TestCase):
    def testMain(self):
        l = [A('a'), A('b')]
        self.assertEqual(repr(l), "['a', 'b']")

if __name__ == '__main__':
    unittest.main()

3

Я погоджуюся з попередньою відповіддю про використання розуміння списку для цього, але ви, звичайно, можете приховати це за функцією, якщо саме це пливе ваш човен.

def is_list(value):
    if type(value) in (list, tuple): return True
    return False

def list_str(value):
    if not is_list(value): return str(value)
    return [list_str(v) for v in value]

Для розваги я зробив list_str () рекурсивно str () все, що міститься в списку.


+1 Це корисно при впровадженні __str__та __repr__окремо
vincent gravitas


0

Цього повинно вистачити.

Під час друку списків, а також інших класів контейнерів, що містяться елементи будуть надруковані за допомогою __repr__, тому що __repr__вони призначені для внутрішнього представлення об'єктів. Якщо ми зателефонуємо: help(object.__repr__)він нам скаже:

Help on wrapper_descriptor:

__repr__(self, /)
    Return repr(self).

І якщо ми help(repr)його зателефонуємо, вийде:

Help on built-in function repr in module builtins:

repr(obj, /)
    Return the canonical string representation of the object.

    For many object types, including most builtins, eval(repr(obj)) == obj.

Якщо __str__він реалізований для об'єкта і __repr__не видає repr(obj)вихід за замовчуванням, як і print(obj)коли реалізується не з них.

Тож єдиний спосіб - це реалізація __repr__для вашого класу. Один з можливих способів зробити це:

class C:           
    def __str__(self):
        return str(f"{self.__class__.__name__} class str ")

C.__repr__=C.__str__       
ci = C()    


print(ci)       #C class str 
print(str(ci))  #C class str 
print(repr(ci)) #C class str 

-3

Вихід, який ви отримуєте, - це лише ім'я модуля об'єкта, ім'я класу, а потім адреса пам'яті у шістнадцятковій формі, оскільки __repr__функція не перекривається.

__str__використовується для представлення рядка об'єкта при використанні print. Але оскільки ви друкуєте список об'єктів, а не повторюєте список, викликати strметод для кожного елемента, він виводить представлення об'єктів.

Щоб __str__викликати функцію, вам потрібно зробити щось подібне:

'my list is %s' % [str(x) for x in myList]

Якщо ви перекриєте __repr__функцію, ви можете використовувати метод друку, як і раніше:

class cell:
    def __init__(self, id):
        self.id = id
    def __str__(self):
        return str(self.id) # Or whatever
    def __repr__(self):
        return str(self) # function invoked when you try and print the whole list.

myList = [cell(1), cell(2), cell(3)]
'my list is %s' % myList

Тоді ви отримаєте " my list is [1, 2, 3]" ваш вихід.


Ця відповідь, здається, відповідає на абсолютно незв'язане питання. Ви впевнені, що помістили його в потрібне місце?
Blckknght

так, Blckknght на цій сторінці, на яку я хотів дати свою відповідь, було посилання на цю сторінку з іншого посту. тому він керував мене тут, і я відповідаю тут, припускаючи, що хлопець, який поставив запитання, приїде сюди ще раз і побачить мою відповідь. незрозумілість !!!
panagiwtis koligas

Якщо інше питання було закрито як дублікат цього, то начебто передбачається, що існуючі тут відповіді повинні вже піклуватися про інше питання. Якщо це не так, то вам слід познайомитися, щоб знову відкрити це питання, а не публікувати тут незрозумілу відповідь, яка майже напевно буде видалена. Тепер, можливо, у вас є що сказати, що не охоплене жодною з 8 інших відповідей тут, але вам потрібно буде зробити свою відповідь сенсом у контексті цієї сторінки, оскільки саме на це питання ви відповідаєте. І не публікуйте двох однакових відповідей!
Blckknght

1
О, хоч тепер, коли я знову дивлюся на це, здається, @charliebeckwith відредагував вашу публікацію зовсім іншим, а не публікувати власну відповідь з якихось незрозумілих причин. Це, як правило, не працює редагування ...
Blckknght

@blckknght Я почав її редагувати ще до того, як зрозумів, наскільки відповідь. Зовсім незрозуміло, чому я продовжував іти.
charliebeckwith
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.