Take the 2-minute tour ×

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

share|improve this question
add comment

3 Answers

up vote 6 down vote accepted

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.

share|improve this answer
add comment

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:


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

share|improve this answer
Great answer. I just want to note that there is a more idiomatic way to express the code you wrote for __str__: def __str__(self): items = ", ".join([str(item) for item in self]); return "[{0}]".format(items) (obviously, split across multiple lines). Main point is that join is the preferred way to insert , (or some other string) in between every item in a list. –  seafangs Jun 14 '13 at 12:19
add comment

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.

share|improve this answer
add comment

Your Answer


