使用__str__表示在Python中的容器中打印对象

时间:2010-04-14 02:44:12

标签: python operator-overloading

我注意到当一个带有重载__str__方法的实例作为参数传递给print函数时,它会按预期打印。但是,将包含其中一个实例的容器传递给print时,它会使用__repr__方法。也就是说,print(x)显示x的正确字符串表示,print(x, y)正常工作,但print([x])print((x, y))打印__repr__代替。

首先,为什么会发生这种情况?其次,有没有办法在这种情况下纠正print的行为?

3 个答案:

答案 0 :(得分:11)

使用对象“__str__的容器的问题是完全不明确 - 如果print L显示[1, 2],这意味着什么? L可以是['1, 2'](其字符串项包含逗号的单个项目列表)或四个2项目列表中的任何一个(因为每个项目可以是字符串或int)。当然,print类型的模糊性很常见,但项目数量的总模糊度(因为每个逗号可以分隔项一部分字符串项目)是决定性的考虑因素。

答案 1 :(得分:5)

我不确定为什么列表的__str__方法确切地返回了包含在其中的对象的__repr__ - 所以我查了一下:{{3} }

  

争论:

     

- 容器拒绝猜测用户想要在str(容器)上看到什么 - 环境,分隔符等等;

     

- repr(item)通常显示类型信息 - 字符串,类名等的撇号

因此更清楚列表中的确切内容(因为对象的字符串表示可能有逗号等)。根据Guido“BDFL”van Rossum的说法,行为并没有消失:

  

让我为大家节省很多   时间,并说我反对这一点   改变,我相信它   会造成太大的干扰   被接受接近beta版。


现在,有两种方法可以解决您的代码问题。

第一个是子类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)的行为仍然存在。

答案 2 :(得分:1)

因为当你打印列表时,通常你是从程序员的角度来看,或者是调试。如果您打算显示列表,则需要以有意义的方式处理其项目,因此使用repr。

如果您希望在容器中打印对象,请定义repr

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

    __repr__ = __str__

当然,repr应该返回一个字符串,可以用作重新创建对象的代码,但是你可以做你想做的事。