在Python的列表中对__str__感到困惑

时间:2012-09-16 15:30:28

标签: python string list printing tostring

来自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]]

我错过了什么?还有什么其他令人讨厌的东西我在做什么? :)

8 个答案:

答案 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__的正确实现可以重新创建对象。在此示例中,它还应包含其他重要成员,例如neighoursdistance

不完整的示例:

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" % unoprint 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