【问题标题】:Confused about __str__ on list in Python [duplicate]对 Python 列表中的 __str__ 感到困惑 [重复]
【发布时间】:2012-09-09 00:21:40
【问题描述】:

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

我明白了

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

我期望的地方

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

我错过了什么?我在做什么其他令人畏惧的事情? :)

【问题讨论】:

  • 有趣的是,它是如何在被问到 7 年后关闭的。

标签: python string list printing tostring


【解决方案1】:

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

所以你也应该覆盖__repr__()。一个简单的

__repr__ = __str__

在类主体的末尾就可以了。

【讨论】:

  • 因为__repr__()在没有__str__()的时候被调用,所以定义__repr__()就足够了。
  • __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
  • @trapicki 是的,尽管这更像是一个指导方针而不是要求。 OP希望问题中提到的列表输出看起来像[[2, 4], [3, 5]],这就是我的回答。类型偏离您提到的准则是很常见的,例如Numpy 的浮点类型只是将数字显示为表示形式,而不是 numpy.float64(42.0),这在列表中会变得非常冗长。
  • 我不是 python 专家,但在这种情况下 eval(repr(obj)) 不会返回实际节点。 @tapicki 的答案更接近真相,但缺少 OP 所要求的基本部分。阅读此答案的人可能想查看quora.com/What-does-repr-method-mean
【解决方案2】:

由于Python对Java的无限优势,Python没有一个,而是两个 toString操作。

一个是__str__,另一个是__repr__

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

__repr__ 可以通过调用repr(obj) 或使用反引号`obj` 在对象上调用。

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

【讨论】:

  • 请注意,作为 repr() 的简写形式的反引号在 Python 3 中消失了。轻微的挑剔:您的第一句话很容易被那些过于认真的人误解。
  • 我意识到我在寻求冒犯幽默挑战者的可能性。我以为我没有越界。你认为我应该编辑我的帖子吗?
  • 这是一个判断电话。可能不是。我只是想我会指出来。
  • 通常很难区分讽刺和讽刺——这可以解释为什么你可以接受的答案从来没有得到很多赞成票。关于“幽默地受到挑战”的评论可能也没有任何帮助。
  • @martineau - 不,它们很容易辨别。无论如何,我认为这是一个很好的答案。我认为幽默应该保持合法,我只是因为你的评论而赞成它。谢谢!
【解决方案3】:

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

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

【讨论】:

  • 又好又清晰!
【解决方案4】:

回答问题

正如在另一个answer 中指出的那样,正如您在PEP 3140 中所读到的,strlist 上调用每个项目__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】:

    好吧,容器对象的__str__ 方法将在其内容上使用repr,而不是str。因此,您可以使用 __repr__ 而不是 __str__,因为您使用的是 ID 作为结果。

    【讨论】:

      【解决方案6】:

      __str__ 仅在对象需要 字符串表示 时调用。

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

      不过,还有另一种神奇的方法叫做__repr__,这是一个对象的表示。当您没有将对象显式转换为字符串时,将使用 representation

      如果您这样做uno.neighbors.append([[str(due),4],[str(tri),5]]),它将按照您的预期进行。

      【讨论】:

        【解决方案7】:

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

        您在输出中看到的内容表明了这一点。

        由于 str 方法以及 print 的工作原理,您可能可以在使用初始全局变量时看到值并使用 print 而不会出现问题,但您将无法执行此操作使用列表,因为存储在该列表中的元素中的内容只是对值的内存位置的引用——如果您想了解更多信息,请阅读别名。

        此外,在使用列表并忘记什么是别名和什么不是别名时,如果您在别名列表中更改原始列表元素的值,您可能会发现它正在更改——因为再次,当您将列表元素设置为等于列表或列表中的元素,新列表仅存储对内存位置的引用(它实际上并不创建特定于该新变量的新内存空间)。这就是 deepcopy 派上用场的地方!

        【讨论】:

          【解决方案8】:

          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
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2016-02-21
            • 1970-01-01
            • 2016-12-27
            • 2015-02-11
            • 1970-01-01
            • 2015-11-07
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多