Используя __ ул. __ представление для печати объектов в контейнерах в Python

Я заметил что когда экземпляр с перегруженным __str__ метод передается print функционируйте как аргумент, он печатает, как предназначено. Однако при передаче контейнера, который содержит один из тех экземпляров к print, это использует __repr__ метод вместо этого. То есть print(x) отображает корректное строковое представление x, и print(x, y) работы правильно, но print([x]) или print((x, y)) печать __repr__ представление вместо этого.

Прежде всего, почему это происходит? Во-вторых, есть ли способ исправить то поведение print при этом обстоятельстве?

9
задан vaultah 9 May 2016 в 20:49
поделиться

3 ответа

Проблема с контейнером, использующим __str__ объектов, заключалась бы в полной неоднозначности - что бы это значило, скажем, если бы print L показал [1, 2]? L может быть ['1, 2'] (одноэлементный список, строковый элемент которого содержит запятую) или любой из четырех двухэлементных списков (поскольку каждый элемент может быть строкой или int). Неоднозначность типа, конечно, характерна для print, но полная неоднозначность количества элементов (поскольку каждая запятая может быть разделителем элементов или частью строкового элемента) стала решающим фактором.

11
ответ дан 4 December 2019 в 12:17
поделиться

Потому что, когда вы печатаете list, как правило, вы смотрите с точки зрения программиста или отлаживаете. Если вы хотели отобразить список, вы должны обработать его элементы осмысленным образом, поэтому используется repr.

Если вы хотите, чтобы ваши объекты печатались в контейнерах, определите repr

class MyObject:
    def __str__(self): return ""

    __repr__ = __str__

Конечно, repr должен возвращать строку, которую можно использовать в качестве кода для воссоздания вашего объекта, но вы можете делать все, что хотите.

1
ответ дан 4 December 2019 в 12:17
поделиться

Я не уверен , почему именно метод __ 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 (контейнер) здесь, чтобы остаться.

5
ответ дан 4 December 2019 в 12:17
поделиться
Другие вопросы по тегам:

Похожие вопросы: