【发布时间】:2012-11-06 19:48:12
【问题描述】:
让我感到困扰的是,一个类的默认 __repr__() 信息量太少了:
>>> class Opaque(object): pass
...
>>> Opaque()
<__main__.Opaque object at 0x7f3ac50eba90>
...所以我一直在考虑如何改进它。经过一番考虑,我想出了这个利用pickle 协议的__getnewargs__() 方法的抽象基类:
from abc import abstractmethod
class Repro(object):
"""Abstract base class for objects with informative ``repr()`` behaviour."""
@abstractmethod
def __getnewargs__(self):
raise NotImplementedError
def __repr__(self):
signature = ", ".join(repr(arg) for arg in self.__getnewargs__())
return "%s(%s)" % (self.__class__.__name__, signature)
这是一个简单的用法示例:
class Transparent(Repro):
"""An example of a ``Repro`` subclass."""
def __init__(self, *args):
self.args = args
def __getnewargs__(self):
return self.args
... 以及由此产生的 repr() 行为:
>>> Transparent("an absurd signature", [1, 2, 3], str)
Transparent('an absurd signature', [1, 2, 3], <type 'str'>)
>>>
现在,我可以看到 Python 默认不立即执行此操作的一个原因 - 要求每个类定义 __getnewargs__() 方法比预期(但不要求)它定义 __repr__() 方法更繁重.
我想知道的是:它有多危险和/或脆弱?顺便说一句,我想不出任何可能出错的地方,除非Repro 实例包含自身,你会得到无限递归......但这是可以解决的,代价是使上面的代码更丑陋。
我还错过了什么?
【问题讨论】:
-
repr在存在诸如__getnewargs__之类的东西之前就已经存在 way 了。你也在滥用一种方法。它是由一个库模块(不是 python 语言核心本身)引入的,目的是做完全不同的事情。还有关键字参数呢?在 python3 中,构造函数只能有关键字参数。此外,我没有看到任何真正的额外好处。可以具有简单字符串表示的对象应该实现__repr__和/或__str__。使用您的方法,您仍然必须重新实现它,或者您必须重新实现__getnewargs__。 -
没有真正的理由为此使用
__getnewargs__本身,是吗?你可以定义一个约定,对象在任意属性中存储一些识别信息(比如_reprInfo),然后__repr__只打印self._reprInfo。 -
@Bakuriu 我怎么滥用它呢?正确实现的
Repro子类将具有正确的泡菜__getnewargs__(),这甚至可能被认为是一个优势。我意识到这不适用于带有关键字参数构造函数的类,但我不会将它与那些......实际上,如果可以的话,我会完全避免在构造函数中使用关键字参数。 -
@BrenBarn 是的,最初我只是想使用类似
_reprInfo属性的东西......但是这样做有什么害处吗? -
@ZeroPiraeus:没有真正的“伤害”,但正如@Bakuriu 所说,它只会在
__repr__和__getnewargs__之间造成不必要的依赖。您也可以重载任何其他随机方法,例如__pos__,并声明现在应该使用该方法返回__repr__数据,但为什么呢?它没有任何优势,而且如果你以后想同时使用__repr__和重载方法来实现各自不同的目的,它只会让人头疼。
标签: python pickle signature abc repr