Python类的repr输出
根据Python 2 的文档,关于 __repr__
的说明是:
如果可能的话,
__repr__
应该看起来像一个有效的 Python 表达式,这个表达式可以用来重新创建一个具有相同值的对象(在适当的环境下)。
那么,为什么内置类的 __repr__
不遵循这个指导原则呢?
举个例子
>>> class A(object):
... pass
>>> repr(A)
"<class 'A'>"
为了符合这个指导原则,默认的 __repr__
应该返回 "A"
,也就是一般来说应该返回 A.__name__
。那为什么它的表现却不一样呢?我觉得这样实现起来应该很简单。
补充:'重现'的范围
我在回答中看到,讨论中并不清楚 repr
应该返回什么。我的理解是,repr
函数应该返回一个字符串,这个字符串能让你重现这个对象:
- 在任意上下文中,并且
- 自动地(也就是说,不需要手动)。
关于第一点:看看一个内置类的例子(取自这个问题):
>>> from datetime import date
>>>
>>> repr(date.today()) # calls date.today().__repr__()
'datetime.date(2009, 1, 16)'
显然,假设的上下文是你使用基本的导入形式,也就是 import datetime
,因为如果你尝试 eval(repr(date.today()))
,datetime
将无法识别。所以关键是 __repr__
不需要从头开始表示这个对象。 只要在社区达成一致的上下文中不模糊就可以了,比如使用直接的模块类型和函数。这听起来合理吧?
关于第二点:我认为,仅仅给出如何重建对象的印象是不够的。str
的目的是帮助调试。
总结
所以我对 repr
的期望是,它能让我对结果使用 eval
。在类的情况下,我不希望得到从头重建类的完整代码。相反,我希望在我的作用域中有一个明确的类引用。"Module.Class"
就足够了。抱歉,Python,但 "<class 'Module.Class'>"
真的不够直观。
4 个回答
我知道这个问题有点老了,但我找到了一种方法来解决它。
我知道的唯一方法是使用一种叫做元类的东西,像这样:
class A(object):
secret = 'a'
class _metaA(type):
@classmethod
def __repr__(cls):
return "<Repr for A: secret:{}>".format(A.secret)
__metaclass__ =_metaA
输出结果是:
>>> A
<Repr for A: secret:a>
因为默认的 __repr__
方法并不知道是用什么语句来创建这个类的。
你引用的文档开头提到“如果可能的话”。由于无法以某种方式表示自定义类以便重新创建它们,所以使用了不同的格式,这种格式适用于所有不容易重建的东西。
如果 repr(A)
只是返回 'A'
,那就没有意义了。你并不是在重新创建 A
,而只是在引用它。"type('A', (object,), {})"
更接近于反映类的构造函数,但这会让不熟悉 Python 类是 type
实例的人感到困惑,而且也无法准确反映方法和属性。
可以把输出和 repr(type)
或 repr(int)
的结果进行比较,它们遵循的是相同的模式。
考虑一个稍微复杂一点的类:
class B(object):
def __init__(self):
self.foo=3
repr
需要返回类似这样的内容:
type("B", (object,), { "__init__": lambda self: setattr(self, "foo", 3) })
你会发现一个问题:并不是所有用 def
语句定义的函数都能用一个简单的 lambda
表达式来表示。稍微改动一下 B
:
class B(object):
def __init__(self, x=2, y, **kwargs):
print "in B.__init__"
你怎么写一个 表达式 来定义 B.__init__
? 你不能使用
lambda self: print "in B.__init__"
因为 lambda
表达式不能包含语句。对于这个简单的类来说,已经不可能用一个单独的 表达式 来完全定义这个类了。