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? :)
__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.
print self.id.__str__()
would work for you, although not that useful for you.
Your __str__
method will be more useful when you say want to print out a grid or struct representation as your program develops.
print self._grid.__str__()
def __str__(self):
"""
Return a string representation of the grid for debugging.
"""
grid_str = ""
for row in range(self._rows):
grid_str += str( self._grid[row] )
grid_str += '\n'
return grid_str
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.
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.
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
The thing about classes, and setting unencumbered global variables equal to some value within the class, is that what your global variable stores is actually the reference to the memory location the value is actually stored.
What you're seeing in your output is indicative of this.
Where you might be able to see the value and use print without issue on the initial global variables you used because of the str method and how print works, you won't be able to do this with lists, because what is stored in the elements within that list is just a reference to the memory location of the value -- read up on aliases, if you'd like to know more.
Additionally, when using lists and losing track of what is an alias and what is not, you might find you're changing the value of the original list element, if you change it in an alias list -- because again, when you set a list element equal to a list or element within a list, the new list only stores the reference to the memory location (it doesn't actually create new memory space specific to that new variable). This is where deepcopy comes in handy!
Well, container objects' __str__
methods will use repr
on their contents, not str
. So you could use __repr__
instead of __str__
, seeing as you're using an ID as the result.
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__
.
Source: Stackoverflow.com