Я заметил что когда экземпляр с перегруженным __str__
метод передается print
функционируйте как аргумент, он печатает, как предназначено. Однако при передаче контейнера, который содержит один из тех экземпляров к print
, это использует __repr__
метод вместо этого. То есть print(x)
отображает корректное строковое представление x
, и print(x, y)
работы правильно, но print([x])
или print((x, y))
печать __repr__
представление вместо этого.
Прежде всего, почему это происходит? Во-вторых, есть ли способ исправить то поведение print
при этом обстоятельстве?
Проблема с контейнером, использующим __str__
объектов, заключалась бы в полной неоднозначности - что бы это значило, скажем, если бы print L
показал [1, 2]
? L
может быть ['1, 2']
(одноэлементный список, строковый элемент которого содержит запятую) или любой из четырех двухэлементных списков (поскольку каждый элемент может быть строкой или int). Неоднозначность типа, конечно, характерна для print
, но полная неоднозначность количества элементов (поскольку каждая запятая может быть разделителем элементов или частью строкового элемента) стала решающим фактором.
Потому что, когда вы печатаете list, как правило, вы смотрите с точки зрения программиста или отлаживаете. Если вы хотели отобразить список, вы должны обработать его элементы осмысленным образом, поэтому используется repr.
Если вы хотите, чтобы ваши объекты печатались в контейнерах, определите repr
class MyObject:
def __str__(self): return ""
__repr__ = __str__
Конечно, repr должен возвращать строку, которую можно использовать в качестве кода для воссоздания вашего объекта, но вы можете делать все, что хотите.
Я не уверен , почему именно метод __ str __
списка возвращает __ repr __
объектов содержится внутри - поэтому я нашел его: [Python-3000] PEP: str (container) должен вызывать str (item), а не repr (item)
Аргументы для него:
- контейнеры отказываются угадайте, что пользователь хочет видеть на str (container) - окружение, разделители и т. д .;
- repr (item) обычно отображает информацию о типе - апострофы вокруг строк, имен классов и т. д.
Так что это больше ясно, что именно находится в списке (поскольку строковое представление объекта может содержать запятые и т. д.). Такое поведение никуда не денется, говорит Гвидо "BDFL" ван Россум:
Позвольте мне сэкономить всем кучу времени и сказать, что я против этого изменения и этого Я считаю, что это вызовет слишком много беспокойства , чтобы его можно было принять так близко к бета-версии.
Есть два способа решить эту проблему для вашего кода.
Первый - создать подкласс list
и реализовать свой собственный метод __ str __
.
class StrList(list):
def __str__(self):
string = "["
for index, item in enumerate(self):
string += str(item)
if index != len(self)-1:
string += ", "
return string + "]"
class myClass(object):
def __str__(self):
return "myClass"
def __repr__(self):
return object.__repr__(self)
А теперь для проверки:
>>> objects = [myClass() for _ in xrange(10)]
>>> print objects
[<__main__.myClass object at 0x02880DB0>, #...
>>> objects = StrList(objects)
>>> print objects
[myClass, myClass, myClass #...
>>> import random
>>> sample = random.sample(objects, 4)
>>> print sample
[<__main__.myClass object at 0x02880F10>, ...
Я лично считаю, что это ужасная идея. Некоторые функции, такие как random.sample
, как показано, на самом деле возвращают объекты list
, даже если вы разбили списки на подклассы. Поэтому, если вы выберете этот путь, может быть много вызовов result = strList (function (mylist))
, что может быть неэффективным. Это также плохая идея, потому что тогда у вас, вероятно, будет половина вашего кода, использующая обычные объекты list
, поскольку вы их не печатаете, а другая половина будет использовать объекты strList
, что может привести к чтобы ваш код стал более беспорядочным и запутанным. Тем не менее, опция есть, и это единственный способ заставить функцию print
(или оператор для 2.x) вести себя так, как вы хотите.
Другое решение - просто написать свою собственную функцию strList ()
, которая возвращает строку в том виде, в каком вы хотите:
def strList(theList):
string = "["
for index, item in enumerate(theList):
string += str(item)
if index != len(theList)-1:
string += ", "
return string + "]"
>>> mylist = [myClass() for _ in xrange(10)]
>>> print strList(mylist)
[myClass, myClass, myClass #...
Оба решения требуют, к сожалению, рефакторинга существующего кода, но поведение str (контейнер)
здесь, чтобы остаться.