SQLAlchemy ORM教程中为何在__repr__值周围加上尖括号?

4 投票
3 回答
921 浏览
提问于 2025-04-17 06:48

这个SQLAlchemy ORM教程使用了这个类:

>>> from sqlalchemy import Column, Integer, String
>>> class User(Base):
...     __tablename__ = 'users'
...
...     id = Column(Integer, primary_key=True)
...     name = Column(String)
...     fullname = Column(String)
...     password = Column(String)
...
...     def __init__(self, name, fullname, password):
...         self.name = name
...         self.fullname = fullname
...         self.password = password
...
...     def __repr__(self):
...        return "<User('%s','%s', '%s')>" % (self.name, self.fullname, self.password)

为什么要费这么大劲去写一个在用eval()执行时能正常工作的字符串,却又用尖括号把它包起来,导致这个功能失效呢?

我知道eval(repr(foo))这个用法并不是__repr__的唯一目的,但在这里故意让它失效似乎还是有点奇怪。难道我漏掉了什么更深层的逻辑,还是说这只是个随意的决定?

3 个回答

0

使用尖括号的一个理由和语义有关。虽然 eval(repr(2)) 总是等于 2,但是 eval(repr(23094823589710L)) 却不等于 23094823589710L,而且我认为 eval(repr(myinstance)) 一般情况下不会等于 instance,特别是对于 mapper 类的实例来说。身份和相等性是否能这样支持,可能还要看类是否有唯一约束或其他特性。

另一个问题是类在命名空间中的可用性。如果某个类恰好不在作用域内,eval(repr(x)) 就会引发 NameError 错误。

再举个复杂的例子:我写了一个自己的库函数(一个元类),它接受一个表名作为字符串,使用 type 动态创建一个类,并且 mapper 已经提供了 __init____str____repr__ 方法,然后返回这个新类。所有这些类的 __name__ 属性都是相同的,因此在我的库函数中,无法支持 eval(repr(x)) is x 或者 eval(repr(x)) == x。所以我在这些类中使用尖括号来表示 repr

我猜,出于这些原因,可能还有其他原因,文档中使用尖括号是为了避免让人产生 eval(repr(x)) is x 总是能被支持的期望。

4

尖括号的用法是Python解释器本身就采用的,所以这个问题更适合问问...GVR?

>>> class Foo(object):
...     pass
... 
>>> f = Foo()
>>> print repr(f)
<__main__.Foo object at 0x1004ab290>
2

要记住,eval 这个东西其实用得不多;为了它去拼接字符串(或者检查这些字符串是否真的能用)其实是多此一举,没必要费那么大劲。

直接把尖括号加上去要简单得多,而且也不会让人想到去用 eval(如果不小心的话,这个东西是挺危险的)。

换句话说,这里并不是故意要让 eval(repr(x)) 出问题。其实在 __repr__ 的输出周围加上尖括号是个习惯而已。

撰写回答