Python __str__ и списки

108

В Java, если я вызываю List.toString (), он автоматически вызывает метод toString () для каждого объекта внутри List. Например, если мой список содержит объекты 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__ для каждого элемента внутри списка (или dict в этом отношении)?

Benhsu
источник
Для справки существует PEP 3140: «str (container) должен вызывать str (item), а не repr (item)» , который был отклонен.
Алексей

Ответы:

134

Строка вызова в списке 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))- он немного короче
anula
4
Одна из проблем заключается в том, что элемент в моем списке также может быть списком
Бреандан Далтон
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__отдельно
винсент гравитас
0

Что-то вроде этого?

a = [1, 2 ,3]
[str(x) for x in a]
# ['1', '2', '3']
Что он делает
источник
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__используется для строкового представления объекта при использовании печати. Но поскольку вы печатаете список объектов, а не выполняете итерацию по списку для вызова 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