Использование представления __str__ для печати объектов в контейнерах в Python - PullRequest
9 голосов
/ 14 апреля 2010

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

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

Ответы [ 3 ]

11 голосов
/ 14 апреля 2010

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

5 голосов
/ 14 апреля 2010

Я не уверен , почему именно метод __str__ списка возвращает __repr__ объектов, содержащихся в нем - поэтому я посмотрел его: [Python-3000] PEP : str (контейнер) должен вызывать str (элемент), а не repr (элемент)

Аргументы за это:

- контейнеры отказываются угадывать, что пользователь хочет видеть на str (контейнер) - окружение, разделители и т. Д .;

- 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(container) остается здесь.

1 голос
/ 14 апреля 2010

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

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

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

    __repr__ = __str__

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...