在 Python 中对__ str__ on 列表感到困惑

从 Java 背景出发,我了解到 __str__类似于 Python 版本的 toString (尽管我确实意识到 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

I get

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

在我预料的地方

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

我错过了什么? 除此之外,我还做了什么令人尴尬的事情? :)

205456 次浏览

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.

Python 有两种不同的方法将对象转换为字符串: str()repr()。打印对象使用 str(); 打印包含对象的列表使用 str()作为列表本身,但是 list.__str__()的实现对单个项目调用 repr()

因此,您还应该覆盖 __repr__()

__repr__ = __str__

在课堂结束的时候,主体部分会起作用。

仅当对象需要 字符串表示法时才调用 __str__

例如 str(uno)print "%s" % unoprint uno

然而,还有另一个神奇的方法称为 __repr__,这是一个对象的 代表。如果没有显式地将对象转换为字符串,则使用 代表

如果你这样做 uno.neighbors.append([[str(due),4],[str(tri),5]])它将做你所期望的。

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

一个是 __str__另一个是 __repr__

__str__将返回一个人类可读的字符串。 __repr__将返回一个内部表示。

可以通过调用 repr(obj)或使用反勾 `obj`对对象调用 __repr__

当打印列表和其他容器类时,包含的元素将使用 __repr__打印。

打印 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

它提供了人类可读的输出版本,而不是“对象”: 示例:

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

returns:

jax is a human

关于类,以及将未受限制的全局变量设置为类中的某个值,全局变量存储的实际上是对实际存储值的内存位置的引用。

您在输出中看到的就是这种情况的证明。

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.

此外,当使用列表时,你可能会发现你正在改变原始列表元素的值,如果你在别名列表中改变它的话——因为再一次,当你设置一个列表元素等于一个列表或者一个列表中的元素时,新列表只存储对内存位置的引用(它实际上并没有创建特定于这个新变量的新内存空间)。这就是深拷贝派上用场的地方!

回答我的问题

正如在另一个 回答中指出的,也正如你可以在 PEP 3140中读到的那样,list上的 str调用每个项目 __repr__。这一点你也无能为力。

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

正确执行

很快,但是错了解决方案是别名 __repr____str__

__repr__ should not be set to __str__ 无条件的. __repr__ should create a 表示形式,它应该看起来像一个有效的 Python 表达式,可用于重新创建具有相同值的对象. In this case, this would rather be Node(2) than 2.

__repr__的正确实现使得重新创建对象成为可能。在这个示例中,它还应该包含其他重要成员,如 neighoursdistance

An 不完整 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)

注意 : 通过 print repr(uno)以及 __eq____ne____cmp__的适当实现,可以重新创建对象并检查是否相等。