Python __repr__和None

时间:2011-10-13 15:32:50

标签: python sqlalchemy repr

我对Python很陌生,目前我需要为SqlAlchemy类提供__repr__。 我有一个可以接受Null值的整数列,SqlAlchemy将其转换为None。 例如:

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

当SqlAlchemy返回__repr__时,在None函数中表示“mystat”字段的正确方法是什么?

6 个答案:

答案 0 :(得分:10)

__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)

答案 1 :(得分:4)

我试图找到一个可以在任何SQLAlchemy对象上使用的通用__repr__方法,并且只找到此页面。所以,我决定写我自己的,这就是我所做的:

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,因此显示将保持一致。

答案 2 :(得分:0)

也许repr(mystat)是你想要的?

答案 3 :(得分:0)

'Null'如果mystat是None mystat

答案 4 :(得分:0)

sqlalchemy-utils的generic_repr装饰器不是提供适合您需求的基于社区的解决方案吗?

它保留为无。

答案 5 :(得分:0)

上一个显示如何覆盖Base.__repr__的答案正是我所需要的。谢谢!在这里,使用f字符串重新编写了Python 3.7+,并重写了flask-sqlalchemy db.Model

def override_default_repr(self):
    class_name = self.__class__.__name__
    attribs = ", ".join(
        [
            f"{k}={self.__dict__[k]!r}"
            for k in sorted(self.__dict__.keys())
            if k[0] != "_"
        ]
    )
    return f"<{class_name}({attribs})>"

db.Model.__repr__ = override_default_repr