Confused about __str__ on list in Python

204,243

Solution 1

Python has two different ways to convert an object to a string: str() and repr(). Printing an object uses str(); printing a list containing an object uses str() for the list itself, but the implementation of list.__str__() calls repr() for the individual items.

So you should also overwrite __repr__(). A simple

__repr__ = __str__

at the end of the class body will do the trick.

Solution 2

Because of the infinite superiority of Python over Java, Python has not one, but two toString operations.

One is __str__, the other is __repr__

__str__ will return a human readable string. __repr__ will return an internal representation.

__repr__ can be invoked on an object by calling repr(obj) or by using backticks `obj`.

When printing lists as well as other container classes, the contained elements will be printed using __repr__.

Solution 3

It provides human readable version of output rather "Object": Example:

class Pet(object):

    def __init__(self, name, species):
        self.name = name
        self.species = species

    def getName(self):
        return self.name

    def getSpecies(self):
        return self.species

    def Norm(self):
        return "%s is a %s" % (self.name, self.species)

if __name__=='__main__':
    a = Pet("jax", "human")
    print a 

returns

<__main__.Pet object at 0x029E2F90>

while code with "str" return something different

class Pet(object):

    def __init__(self, name, species):
        self.name = name
        self.species = species

    def getName(self):
        return self.name

    def getSpecies(self):
        return self.species

    def __str__(self):
        return "%s is a %s" % (self.name, self.species)

if __name__=='__main__':
    a = Pet("jax", "human")
    print a 

returns:

jax is a human

Solution 4

Answer to the question

As pointed out in another answer and as you can read in PEP 3140, str on a list calls for each item __repr__. There is not much you can do about that part.

If you implement __repr__, you will get something more descriptive, but if implemented correctly, not exactly what you expected.

Proper implementation

The fast, but wrong solution is to alias __repr__ to __str__.

__repr__ should not be set to __str__ unconditionally. __repr__ should create a representation, that should look like a valid Python expression that could be used to recreate an object with the same value. In this case, this would rather be Node(2) than 2.

A proper implementation of __repr__ makes it possible to recreate the object. In this example, it should also contain the other significant members, like neighours and distance.

An incomplete example:

class Node:

    def __init__(self, id, neighbours=[], distance=0):
        self.id = id
        self.neighbours = neighbours
        self.distance = distance


    def __str__(self):
        return str(self.id)


    def __repr__(self):
        return "Node(id={0.id}, neighbours={0.neighbours!r}, distance={0.distance})".format(self)
        # in an elaborate implementation, members that have the default
        # value could be left out, but this would hide some information


uno = Node(1)    
due = Node(2)    
tri = Node(3)    
qua = Node(4)

print uno
print str(uno)
print repr(uno)

uno.neighbours.append([[due, 4], [tri, 5]])

print uno
print uno.neighbours
print repr(uno)

Note: print repr(uno) together with a proper implementation of __eq__ and __ne__ or __cmp__ would allow to recreate the object and check for equality.

Solution 5

__str__ is only called when a string representation is required of an object.

For example str(uno), print "%s" % uno or print uno

However, there is another magic method called __repr__ this is the representation of an object. When you don't explicitly convert the object to a string, then the representation is used.

If you do this uno.neighbors.append([[str(due),4],[str(tri),5]]) it will do what you expect.

Share:
204,243
Christofer Ohlsson
Author by

Christofer Ohlsson

I make the beep beep go boop beep.

Updated on February 21, 2020

Comments

  • Christofer Ohlsson
    Christofer Ohlsson about 4 years

    Coming from a Java background, I understand that __str__ is something like a Python version of toString (while I do realize that Python is the older language).

    So, I have defined a little class along with an __str__ method as follows:

    class Node:
    
        def __init__(self, id):
            self.id = id
            self.neighbours = []
            self.distance = 0
    
    
        def __str__(self):
            return str(self.id)
    

    I then create a few instances of it:

    uno = Node(1)    
    due = Node(2)    
    tri = Node(3)    
    qua = Node(4)
    

    Now, the expected behaviour when trying to print one of these objects is that it's associated value gets printed. This also happens.

    print uno
    

    yields

    1
    

    But when I do the following:

    uno.neighbours.append([[due, 4], [tri, 5]])
    

    and then

    print uno.neighbours
    

    I get

    [[[<__main__.Node instance at 0x00000000023A6C48>, 4], [<__main__.Node instance at 0x00000000023A6D08>, 5]]]
    

    Where I expected

    [[2, 4], [3, 5]]
    

    What am I missing? And what otherwise cringe-worthy stuff am I doing? :)

  • Steven Rumbalski
    Steven Rumbalski over 11 years
    Note that backticks as shorthand for repr() goes away in Python 3. Minor nit-pick: Your first sentence is liable to misinterpretation by those who take things too seriously.
  • Hans Then
    Hans Then over 11 years
    I realize I am courting the possibility of offending the humorically challenged. I thought I did not cross the line. Do you think I should edit my post?
  • Steven Rumbalski
    Steven Rumbalski over 11 years
    It's a judgement call. Probably not. I just thought I'd point it out.
  • martineau
    martineau about 10 years
    It's often difficult to tell the difference between irony and sarcasm -- which may explain why your otherwise acceptable answer hasn't ever received many up-votes. The comment about "humorically challenged" likely didn't help any, either.
  • glglgl
    glglgl over 8 years
    As __repr__() is called when there is no __str__(), it is enough to define __repr__().
  • AsheKetchum
    AsheKetchum over 6 years
    Nice and clear!
  • trapicki
    trapicki about 6 years
    __repr__ should not be set to __str__ unconditionally. __repr__ should create a "representation, that should look like a valid Python expression that could be used to recreate an object with the same value" In this case, this would rather be Node(2) than 2.
  • Sven Marnach
    Sven Marnach about 6 years
    @trapicki True, though that's more of a guideline rather than a requirement. The OP wanted the list output mentioned in the question to look like [[2, 4], [3, 5]], and this is what I answered. It's quite common for types to deviate from the guideline you mentioned, e.g. Numpy's floating point types simply show numbers as representations rather than numpy.float64(42.0), which would become quite verbose in lists.
  • user3081519
    user3081519 almost 6 years
    I am no python expert, but in this case eval(repr(obj)) won't return the actual node. The answer by @tapicki is a bit closer to truth but lacks the essential part asked by OP. Whoever reads this answer might want to check out quora.com/What-does-repr-method-mean
  • RW77
    RW77 almost 3 years
    @martineau - No, they are quite easy to discern. Anyway, I think it's a great answer. I think humor should stay legal, and I upvoted it just because of your comment. Thanks!
  • martineau
    martineau almost 3 years
    @RW77: They indeed can be hard to discern because sarcasm is a form of irony and no one can see you smiling in an all text answer — plus Stackoverlow isn't humor blog. ;¬)