简体   繁体   English

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

[英]Using __str__ representation for printing objects in containers in Python

I've noticed that when an instance with an overloaded __str__ method is passed to the print function as an argument, it prints as intended.我注意到,当一个带有重载__str__方法的实例作为参数传递给print函数时,它会按预期打印。 However, when passing a container that contains one of those instances to print , it uses the __repr__ method instead.但是,当将包含这些实例之一的容器传递给print ,它会改用__repr__方法。 That is to say, print(x) displays the correct string representation of x , and print(x, y) works correctly, but print([x]) or print((x, y)) prints the __repr__ representation instead.也就是说, print(x)显示器的正确字符串表示x ,和print(x, y)工作正常,但print([x])print((x, y))打印__repr__表示来代替。

First off, why does this happen?首先,为什么会发生这种情况? Secondly, is there a way to correct that behavior of print in this circumstance?其次,在这种情况下,有没有办法纠正这种print行为?

The problem with the container using the objects' __str__ would be the total ambiguity -- what would it mean, say, if print L showed [1, 2] ?使用对象的__str__的容器的问题是总的歧义——比如说,如果print L显示[1, 2] ,这意味着什么? L could be ['1, 2'] (a single item list whose string item contains a comma) or any of four 2-item lists (since each item can be a string or int). L可以是['1, 2'] (字符串项包含逗号的单个项列表)或四个 2 项列表中的任何一个(因为每个项都可以是字符串或整数)。 The ambiguity of type is common for print of course, but the total ambiguity for number of items (since each comma could be delimiting items or part of a string item) was the decisive consideration.类型的歧义当然对于print很常见,但项目数量的总歧义(因为每个逗号可能是分隔项目字符串项目的一部分)是决定性的考虑因素。

I'm not sure why exactly the __str__ method of a list returns the __repr__ of the objects contained within - so I looked it up: [Python-3000] PEP: str(container) should call str(item), not repr(item)我不确定为什么列表的__str__方法会返回包含在其中的对象的__repr__ - 所以我__repr__了一下: [Python-3000] PEP:str(container) 应该调用 str(item),而不是 repr(item) )

Arguments for it:其论据:

-- containers refuse to guess what the user wants to see on str(container) - surroundings, delimiters, and so on; -- 容器拒绝猜测用户想在 str(container) 上看到什么——环境、分隔符等;

-- repr(item) usually displays type information - apostrophes around strings, class names, etc. -- repr(item) 通常显示类型信息 - 字符串、类名等周围的撇号。

So it's more clear about what exactly is in the list (since the object's string representation could have commas, etc.).所以更清楚列表中的确切内容(因为对象的字符串表示可能有逗号等)。 The behavior is not going away, per Guido "BDFL" van Rossum:根据 Guido "BDFL" van Rossum 的说法,这种行为不会消失:

Let me just save everyone a lot of time and say that I'm opposed to this change, and that I believe that it would cause way too much disturbance to be accepted this close to beta.让我为大家节省很多时间,并说我反对这种更改,并且我相信它会引起太多的干扰,以至于在接近测试版时被接受。


Now, there are two ways to resolve this issue for your code.现在,有两种方法可以为您的代码解决此问题。

The first is to subclass list and implement your own __str__ method.第一个是子类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)

And now to test it:现在来测试一下:

>>> 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>, ...

I personally think this is a terrible idea.我个人认为这是一个可怕的想法。 Some functions - such as random.sample , as demonstrated - actually return list objects - even if you sub-classed lists.一些函数 - 例如random.sample ,如演示 - 实际上返回list对象 - 即使您对列表进行了子类化。 So if you take this route there may be a lot of result = strList(function(mylist)) calls, which could be inefficient.所以如果你走这条路线,可能会有很多result = strList(function(mylist))调用,这可能是低效的。 It's also a bad idea because then you'll probably have half of your code using regular list objects since you don't print them and the other half using strList objects, which can lead to your code getting messier and more confusing.这也是一个坏主意,因为那样您的代码可能有一半使用常规list对象,因为您不打印它们,而另一半使用strList对象,这会导致您的代码变得更加混乱和混乱。 Still, the option is there, and this is the only way to get the print function (or statement, for 2.x) to behave the way you want it to.尽管如此,选项仍然存在,这是使print函数(或语句,对于 2.x)按照您希望的方式运行的唯一方法。

The other solution is just to write your own function strList() which returns the string the way you want it:另一种解决方案是编写自己的函数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 #...

Both solutions require that you refactor existing code, unfortunately - but the behavior of str(container) is here to stay.不幸的是,这两种解决方案都要求您重构现有代码 - 但str(container)的行为将继续存在。

Because when you print the list, generally you're looking from the programmer's perspective, or debugging.因为当您打印列表时,通常您是从程序员的角度来看的,或者说是调试。 If you meant to display the list, you'd process its items in a meaningful way, so repr is used.如果您打算显示列表,您将以有意义的方式处理其项目,因此使用 repr。

If you want your objects to be printed while in containers, define repr如果您希望在容器中打印对象,请定义 repr

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

    __repr__ = __str__

Of course, repr should return a string that could be used as code to recreate your object, but you can do what you want.当然, repr 应该返回一个字符串,该字符串可以用作重新创建对象的代码,但是您可以随心所欲。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM