开发者

Using __str__ representation for printing objects in containers

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开发者_C百科. However, when passing a container that contains one of those instances to print, it uses the __repr__ method instead. 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.

First off, why does this happen? Secondly, is there a way to correct that behavior of print in this circumstance?


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]? 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). 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.


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)

Arguments for it:

-- containers refuse to guess what the user wants to see on str(container) - surroundings, delimiters, and so on;

-- repr(item) usually displays type information - apostrophes around strings, class names, etc.

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:

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.

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. So if you take this route there may be a lot of result = strList(function(mylist)) calls, which could be inefficient. 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. 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.

The other solution is just to write your own function strList() which returns the string the way you want it:

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.


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.

If you want your objects to be printed while in containers, define 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.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜