Confused about __str__ on list in Python
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.
Comments
-
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 over 11 yearsNote 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 over 11 yearsI 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 over 11 yearsIt's a judgement call. Probably not. I just thought I'd point it out.
-
martineau about 10 yearsIt'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 over 8 yearsAs
__repr__()
is called when there is no__str__()
, it is enough to define__repr__()
. -
AsheKetchum over 6 yearsNice and clear!
-
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 beNode(2)
than2
. -
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 thannumpy.float64(42.0)
, which would become quite verbose in lists. -
user3081519 almost 6 yearsI 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 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 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.
;¬)