来自Java背景,我知道__str__
类似于toString的Python版本(虽然我确实认识到Python是旧语言)。
所以,我已经定义了一个小类以及__str__
方法,如下所示:
class Node:
def __init__(self, id):
self.id = id
self.neighbours = []
self.distance = 0
def __str__(self):
return str(self.id)
然后我创建了一些它的实例:
uno = Node(1)
due = Node(2)
tri = Node(3)
qua = Node(4)
现在,尝试打印其中一个对象时的预期行为是打印相关值。这也会发生。
print uno
产量
1
但是当我做以下事情时:
uno.neighbours.append([[due, 4], [tri, 5]])
然后
print uno.neighbours
我得到了
[[[<__main__.Node instance at 0x00000000023A6C48>, 4], [<__main__.Node instance at 0x00000000023A6D08>, 5]]]
我期待的地方
[[2, 4], [3, 5]]
我错过了什么?还有什么其他令人讨厌的东西我在做什么? :)
答案 0 :(得分:131)
Python有两种不同的方法将对象转换为字符串:str()
和repr()
。打印对象使用str()
;打印包含对象的列表会使用str()
作为列表本身,但list.__str__()
的实现会为各个项目调用repr()
。
所以你也应该覆盖__repr__()
。一个简单的
__repr__ = __str__
在课堂结束时,会做到这一点。
答案 1 :(得分:35)
由于Python相对于Java的无限优势,Python没有一个,而是两个 toString操作。
一个是__str__
,另一个是__repr__
__str__
将返回一个人类可读的字符串。
__repr__
将返回内部表示。
__repr__
或使用反引号repr(obj)
在对象上调用 `obj`
。
打印列表以及其他容器类时,将使用__repr__
打印包含的元素。
答案 2 :(得分:24)
它提供人类可读的输出版本,而不是“对象”:示例:
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
返回
<__main__.Pet object at 0x029E2F90>
而带有“ str ”的代码会返回不同的内容
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
返回:
jax is a human
答案 3 :(得分:8)
好吧,容器对象'__str__
方法会在其内容上使用repr
,而不是str
。因此,您可以使用__repr__
代替__str__
,因为您正在使用ID作为结果。
答案 4 :(得分:6)
正如另一个answer中指出的那样,您可以在PEP 3140中阅读str
list
来调用每个项目__repr__
。关于那部分,你无能为力。
如果您实施__repr__
,您将获得更具描述性的内容,但如果实施得当,则不完全符合您的预期。
快速但错误的解决方案是将__repr__
别名为__str__
。
__repr__
不应无条件地设置为__str__
。 __repr__
应该创建一个representation, that should look like a valid Python expression that could be used to recreate an object with the same value。在这种情况下,这应该是Node(2)
而不是2
。
__repr__
的正确实现可以重新创建对象。在此示例中,它还应包含其他重要成员,例如neighours
和distance
。
不完整的示例:
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)
注意:print repr(uno)
以及__eq__
和__ne__
或__cmp__
的正确实现将允许重新创建对象并检查是否相等
答案 5 :(得分:4)
__str__
。
例如str(uno)
,print "%s" % uno
或print uno
但是,还有另一种称为__repr__
的魔术方法,它是对象的表示。如果您没有将对象显式转换为字符串,则使用表示。
如果您执行此操作uno.neighbors.append([[str(due),4],[str(tri),5]])
,它将按预期执行。
答案 6 :(得分:1)
关于类的事情,以及将未受阻碍的全局变量设置为等于类中的某个值,是全局变量存储的实际上是对实际存储值的内存位置的引用。
您在输出中看到的内容表明了这一点。
您可能能够看到该值并使用print而不会因为 str 方法而使用的初始全局变量以及打印的工作原理,您将无法执行此操作使用列表,因为存储在该列表中的元素中的内容只是对值的内存位置的引用 - 如果您想了解更多信息,请阅读别名。
此外,当使用列表并且忘记什么是别名和什么不是时,您可能会发现您正在更改原始列表元素的值,如果您在别名列表中更改它 - 因为再次,当如果将列表元素设置为等于列表中的列表或元素,则新列表仅存储对内存位置的引用(它实际上不会创建特定于该新变量的新内存空间)。这是深度拷贝派上用场的地方!
答案 7 :(得分:-1)
print self.id.__str__()
对您有用,虽然对您没有用。
当您说要在程序开发时打印出网格或结构表示时,您的__str__
方法会更有用。
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