Python __repr__ 和无

Posted

技术标签:

【中文标题】Python __repr__ 和无【英文标题】:Python __repr__ and None 【发布时间】:2011-12-07 01:59:25 【问题描述】:

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

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

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

【问题讨论】:

__repr__() 只返回 python 对象的字符串表示形式。我不确定是否有“正确”的方式来实现它。 你明白在你的代码示例中你创建的是类属性,而不是实例属性,对吧? @KarlKnechtel 现在我在网上搜索了我知道,谢谢。这就是为什么我写我是 Python 新手 :) 【参考方案1】:

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

【讨论】:

哇,谢谢。我错过了repr 的尖括号(即&lt; ... &gt;)约定,如果我们不能返回“创建对象的代码”。另请注意,str 回退到 repr【参考方案2】:

我试图找到一个可用于任何 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,这样显示会保持一致。

【讨论】:

【参考方案3】:

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

它保留为无。

【讨论】:

这是正确答案。不幸的是,所有其他答案都早于这个解决方案,但这是人们现在应该使用的。但是,将装饰器包装在检查开发环境的东西中以防止生产中的数据泄漏可能是有益的。【参考方案4】:

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

【讨论】:

【参考方案5】:

'Null' if mystat is None else mystat

【讨论】:

【参考方案6】:

之前显示如何覆盖Base.__repr__ 的答案正是我所需要的。谢谢!在这里,它使用 Python 3.7+ 的 f 字符串重写并覆盖了 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

【讨论】:

以上是关于Python __repr__ 和无的主要内容,如果未能解决你的问题,请参考以下文章

Python __repr__ 用于所有成员变量

python模块可以有__repr__吗?

python __str__ , __repr__区别

python 重写__repr__与__str__函数

Python - 嵌套的 __repr__ 将换行符恢复为“\\n”

Python中__str__和__repr__的区别