Python中的__repr__和None

5 投票
6 回答
12044 浏览
提问于 2025-04-17 04:15

我刚开始学习Python,现在需要为一个SqlAlchemy类写一个__repr__方法。这个类里有一个整数类型的字段,它可以接受Null值,而SqlAlchemy会把这个值转换成None。举个例子:

class Stats(Base):
   __tablename__ = "stats"
   description = Column(String(2000))
   mystat = Column(Integer, nullable=True)

当SqlAlchemy返回None时,应该如何在__repr__方法中正确地表示“mystat”这个字段呢?

6 个回答

3

难道不是因为 sqlalchemy-utils 里的 generic_repr 装饰器提供了一个社区开发的解决方案,正好符合你的需求吗?

它的结果是 None。

8

我在找一个通用的 __repr__ 方法,可以在任何 SQLAlchemy 对象上使用,结果只找到这一页。于是我决定自己写一个,下面是我做的:

from sqlalchemy.ext.declarative import declarative_base
Base = declarative_base()

if __debug__:
    # monkey-patch in useful repr() for all objects, but only in dev
    def tablerepr(self):
        return "<{}({})>".format(
            self.__class__.__name__,
            ', '.join(
                ["{}={}".format(k, repr(self.__dict__[k]))
                    for k in sorted(self.__dict__.keys())
                    if k[0] != '_']
            )
        )
    Base.__repr__ = tablerepr

这个方法扩展了 Base 类,可以打印出特定实例的内容。所以,现在我创建的每一个继承自 Base 的对象都会有一个 __repr__ 方法,它不仅仅打印类名和实例的哈希值。

编辑:我添加了一个 if __debug__,因为这个改动可能会在生产环境中泄露一些你不想泄露的信息。我还添加了 sorted,这样显示的内容会保持一致。

12

__repr__ 方法应该返回一个描述对象的字符串。如果可能的话,这个字符串应该是一个有效的 Python 表达式,能够生成一个相同的对象。这对于像 intstr 这样的内置类型是成立的:

>>> x = 'foo'
>>> eval(repr(x)) == x
True

如果不能做到这一点,那么它应该是一个形如 '<...>' 的字符串,能够唯一地描述这个对象。默认的 __repr__ 就是一个这样的例子:

>>> class Foo(object):
        pass
>>>
>>> repr(Foo())
'<__main__.Foo object at 0x02A74E50>'

它使用对象在内存中的地址来唯一标识这个对象。当然,地址并不能告诉我们太多关于这个对象的信息,所以重写 __repr__ 方法,返回一个描述对象状态的字符串是很有用的。

对象的状态是由它包含的其他对象定义的,因此在你的描述中包含它们的 repr 是有意义的。这正是 listdict 所做的:

>>> repr(['bar', Foo()])
"['bar', <__main__.Foo object at 0x02A74710>]"

在你的情况下,状态在你的 Column 属性中,所以你想使用它们的 repr。你可以使用 %r 格式化来实现这一点,它会插入参数的 repr()

def __repr__(self):
    return '<Stats: description=%r, mystat=%r>' % (self.description, self.mystat)

使用新格式化的等效方法:

def __repr__(self):
    return '<Stats: description={0.description!r}, mystat={0.mystat!r}>'.format(self)

撰写回答