【问题标题】:Using __str__ representation for printing objects in containers使用 __str__ 表示在容器中打印对象
【发布时间】:2011-02-07 17:43:43
【问题描述】:

我注意到,当具有重载 __str__ 方法的实例作为参数传递给 print 函数时,它会按预期打印。但是,当将包含这些实例之一的容器传递给print 时,它会改用__repr__ 方法。也就是说,print(x) 显示x 的正确字符串表示,print(x, y) 工作正常,但print([x])print((x, y)) 打印的是__repr__ 表示。

首先,为什么会发生这种情况?其次,在这种情况下,有没有办法纠正print 的这种行为?

【问题讨论】:

    标签: python operator-overloading


    【解决方案1】:

    使用对象的__str__ 的容器的问题将是完全的歧义——比如说,如果print L 显示[1, 2],这意味着什么? L 可以是 ['1, 2'](一个单项列表,其字符串项包含逗号)或四个 2 项列表中的任何一个(因为每个项都可以是字符串或 int)。当然,类型的歧义对于print 来说很常见,但是项目数量的总歧义(因为每个逗号可以分隔项目字符串项目的一部分)是决定性的考虑因素。

    【讨论】:

      【解决方案2】:

      我不确定 为什么 列表的 __str__ 方法究竟会返回其中包含的对象的 __repr__ - 所以我查了一下:[Python-3000] PEP: str(container) should call str(item), not repr(item)

      它的论据:

      --容器拒绝猜测用户想在str(container)上看到什么——环境、分隔符等等;

      -- repr(item) 通常显示类型信息 - 字符串、类名等周围的撇号。

      所以更清楚地知道列表中的确切内容(因为对象的字符串表示可能有逗号等)。根据 Guido "BDFL" van Rossum 的说法,这种行为不会消失:

      让我为大家节省很多 时间并说我反对这个 改变,我相信它 会造成太多的干扰 在接近测试版的情况下被接受。


      现在,有两种方法可以为您的代码解决此问题。

      首先是继承list并实现自己的__str__方法。

      class StrList(list):
          def __str__(self):
              string = "["
              for index, item in enumerate(self):
                  string += str(item)
                  if index != len(self)-1:
                      string += ", "
              return string + "]"
      
      class myClass(object):
          def __str__(self):
              return "myClass"
      
          def __repr__(self):
              return object.__repr__(self)
      

      现在来测试一下:

      >>> objects = [myClass() for _ in xrange(10)]
      >>> print objects
      [<__main__.myClass object at 0x02880DB0>, #...
      >>> objects = StrList(objects)
      >>> print objects
      [myClass, myClass, myClass #...
      >>> import random
      >>> sample = random.sample(objects, 4)
      >>> print sample
      [<__main__.myClass object at 0x02880F10>, ...
      

      我个人认为这是一个糟糕的主意。一些函数——例如random.sample,如图所示——实际上返回list对象——即使你对列表进行了子分类。所以如果你走这条路,可能会有很多result = strList(function(mylist)) 调用,这可能是低效的。这也是一个坏主意,因为您可能有一半的代码使用常规的list 对象,因为您不打印它们,而另一半使用strList 对象,这可能导致您的代码变得更加混乱和混乱.尽管如此,选项仍然存在,这是让 print 函数(或 2.x 中的语句)按照您希望的方式运行的唯一方法。

      另一种解决方案是编写你自己的函数strList(),它以你想要的方式返回字符串:

      def strList(theList):
          string = "["
          for index, item in enumerate(theList):
              string += str(item)
              if index != len(theList)-1:
                  string += ", "
          return string + "]"
      
      >>> mylist = [myClass() for _ in xrange(10)]
      >>> print strList(mylist)
      [myClass, myClass, myClass #...
      

      不幸的是,这两种解决方案都要求您重构现有代码 - 但 str(container) 的行为将继续存在。

      【讨论】:

      • 很好的答案。我只想指出,有一种更惯用的方式来表达您为__str__ 编写的代码:def __str__(self): items = ", ".join([str(item) for item in self]); return "[{0}]".format(items)(显然,分成多行)。要点是join 是在列表中的每个项目之间插入, (或其他字符串)的首选方式。
      【解决方案3】:

      因为当你打印列表时,通常你是从程序员的角度来看,或者调试。如果您打算显示列表,您将以有意义的方式处理其项目,因此使用 repr。

      如果您希望在容器中打印对象,请定义 repr

      class MyObject:
          def __str__(self): return ""
      
          __repr__ = __str__
      

      当然,repr 应该返回一个字符串,该字符串可以用作代码来重新创建您的对象,但您可以为所欲为。

      【讨论】:

        猜你喜欢
        • 2012-11-15
        • 2023-03-23
        • 2011-04-03
        • 1970-01-01
        • 2019-05-08
        • 1970-01-01
        • 2022-11-23
        • 2021-04-16
        • 2015-01-10
        相关资源
        最近更新 更多