为了账号安全,请及时绑定邮箱和手机立即绑定

使用集合类 Python 的 __repr__ 的最佳实践是什么?

使用集合类 Python 的 __repr__ 的最佳实践是什么?

FFIVE 2023-03-08 10:01:27
我有一个自定义 Python 类,它本质上封装了list某种对象,我想知道我应该如何实现它的__repr__功能。我很想选择以下内容:class MyCollection:   def __init__(self, objects = []):      self._objects = []      self._objects.extend(objects)   def __repr__(self):      return f"MyCollection({self._objects})"这具有生成完整描述类实例的有效 Python 输出的优点。然而,在我的真实情况下,对象列表可能相当大,每个对象本身可能有一个很大的 repr(它们本身就是数组)。在这种情况下的最佳做法是什么?接受 repr 可能通常是一个很长的字符串?是否存在与此相关的潜在问题(调试器 UI 等)?我应该使用分号实施某种缩短方案吗?如果是这样,是否有一种好的/标准的方法来实现这一目标?或者我应该完全跳过列出集合的内容吗?
查看完整描述

1 回答

?
红糖糍粑

TA贡献1815条经验 获得超6个赞

官方文档将此概述为您应该如何处理 __repr__:

由 repr() 内置函数调用以计算对象的“官方”字符串表示形式。如果可能的话,这应该看起来像一个有效的 Python 表达式,可用于重新创建具有相同值的对象(给定适当的环境)。如果这不可能,则应返回 <...some useful description...> 形式的字符串。返回值必须是字符串对象。如果一个类定义了 __repr__() 而不是 __str__(),那么当需要该类实例的“非正式”字符串表示时,也会使用 __repr__()。

这通常用于调试,因此表示信息丰富且明确非常重要。

Python 3__repr__文档

列表、字符串、集合、元组和字典都在它们的 __repr__ 方法中打印出它们的整个集合。

您当前的代码看起来完全遵循文档建议的示例。尽管我建议更改您的 __init__ 方法,使其看起来更像这样:

class MyCollection:

   def __init__(self, objects=None):

       if objects is None:

           objects = []

      self._objects = objects


   def __repr__(self):

      return f"MyCollection({self._objects})"

您通常希望避免使用可变对象作为默认参数。从技术上讲,由于您的方法是使用 extend (它制作列表的副本)实现的,它仍然可以很好地工作,但是 Python 的文档仍然建议您避免这种情况。


不使用可变对象作为默认值是一种很好的编程习惯。相反,使用 None 作为默认值并在函数内部检查参数是否为 None 并创建一个新的列表/字典/无论是否是。


https://docs.python.org/3/faq/programming.html#why-are-default-values-shared-between-objects


如果您对另一个库如何以不同方式处理它感兴趣,当数组长度大于 1,000 时,Numpy 数组的 repr 仅显示前三项和后三项。它还对项目进行格式化,以便它们都使用相同数量的空间(在下面的示例中,1000 占用四个空间,因此 0 必须用另外三个空间填充才能匹配)。


>>> repr(np.array([i for i in range(1001)]))

'array([   0,    1,    2, ...,  998,  999, 1000])'

要模仿这种 numpy 数组样式,您可以在您的类中实现这样的 __repr__ 方法:


class MyCollection:

   def __init__(self, objects=None):

      if objects is None:

          objects = []

      self._objects = objects


   def __repr__(self):

       # If length is less than 1,000 return the full list.

      if len(self._objects) < 1000:

          return f"MyCollection({self._objects})"

      else:

          # Get the first and last three items

          items_to_display = self._objects[:3] + self._objects[-3:]

          # Find the which item has the longest repr

          max_length_repr = max(items_to_display, key=lambda x: len(repr(x)))

          # Get the length of the item with the longest repr

          padding = len(repr(max_length_repr))

          # Create a list of the reprs of each item and apply the padding

          values = [repr(item).rjust(padding) for item in items_to_display]

          # Insert the '...' inbetween the 3rd and 4th item

          values.insert(3, '...')

          # Convert the list to a string joined by commas

          array_as_string = ', '.join(values)

          return f"MyCollection([{array_as_string}])"


>>> repr(MyCollection([1,2,3,4]))

'MyCollection([1, 2, 3, 4])'


>>> repr(MyCollection([i for i in range(1001)]))

'MyCollection([   0,    1,    2, ...,  998,  999, 1000])'


查看完整回答
反对 回复 2023-03-08
  • 1 回答
  • 0 关注
  • 71 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信