Python中所有成员变量的__repr__方法

11

为一个带有成员变量xy的类Foo实现__repr__方法,是否有一种自动填充字符串的方法?以下是一个不起作用的示例:

class Foo(object):
    def __init__(self, x, y):
        self.x = x
        self.y = y
    def __repr__(self):
        return "Foo({})".format(**self.__dict__)

>>> foo = Foo(42, 66)
>>> print(foo)
IndexError: tuple index out of range

还有一个:

from pprint import pprint
class Foo(object):
    def __init__(self, x, y):
        self.x = x
        self.y = y
    def __repr__(self):
        return "Foo({})".format(pprint(self.__dict__))

>>> foo = Foo(42, 66)
>>> print(foo)
{'x': 42, 'y': 66}
Foo(None)

是的,我可以将这个方法定义为

    def __repr__(self):
        return "Foo({x={}, y={}})".format(self.x, self.x)

但是当成员变量很多时,这会变得很繁琐。

4个回答

28

当我想要类似于那样的东西时,我会将其用作混合。

class SimpleRepr(object):
    """A mixin implementing a simple __repr__."""
    def __repr__(self):
        return "<{klass} @{id:x} {attrs}>".format(
            klass=self.__class__.__name__,
            id=id(self) & 0xFFFFFF,
            attrs=" ".join("{}={!r}".format(k, v) for k, v in self.__dict__.items()),
            )

它提供了类名、(缩短的)ID 和所有属性。


不错!真是高雅的。 - Bubble Bubble Bubble Gut
1
为什么它不是默认的 object.__repr__ 实现? - Géry Ogam
请注意,为避免返回代理对象的虚拟类名(参见此答案),应该使用type(self).__name__而不是self.__class__.__name__ - Géry Ogam
@Maggyero:如果你正在编写一个代理对象,你可能根本不应该使用这个 mixin。无论你选择哪个类名,它都会给出误导性的结果。 - user2357112
1
我建议使用完整的ID而不是缩写 - 人们会对@符号后面的数字做出假设,而我认为缩短输出并不值得因缩写ID而引起的混乱。 - user2357112
@Maggyero 这不是默认设置,如果存在循环引用,可能会导致无限递归。请参见 https://dev59.com/KHM_5IYBdhLWcg3wTRPL#2626364。 - xlm

9
我认为你想要的是这样的东西:
    def __repr__(self):
        return "Foo({!r})".format(self.__dict__)

这将在字符串中添加 repr(self.__dict__),使用格式说明符中的 !r 告诉 format() 调用项的 __repr__()

在此处查看“转换字段”:https://docs.python.org/zh-cn/3/library/string.html#format-string-syntax


根据 Ned Batchelder 的答案,您可以使用以下代码替换上面的行:

return "{}({!r})".format(self.__class__.__name__, self.__dict__)

为了更通用的方法。

1
如果 self 指向本身,这样的实现会导致无限循环,因此您必须先过滤 self.__dict__ - jlaurens

0

很好的例子!

为了更好的输出,最好将简单的return "\n{!r}".format(self.__dict__)放在适当的位置,并在根目录下完整打印return "Class name: '{}' \n{!r}".format(self.__class__.__name__, self.__dict__)


0
通常情况下,__repr__ 的意思是你可以复制粘贴结果,并且可以轻松地再次用于创建新对象。因此,下面的方法可能看起来有点巧妙,但它能够完成工作。同时,请注意我们需要对字符串类型的参数和数值类型的参数进行不同的处理。
class Foo:
    def __init__(self, x, y):
        self.x = x
        self.y = y

    def __repr__(self):
        repr_str = f"{self.__class__.__name__}"
        repr_str += '('
        
        for key, val in self.__dict__.items():
            val       = f"'{val}'" if isinstance(val, str) else val
            repr_str += f"{key}={val}, "
        
        return repr_str.strip(", ") + ')'


>>> foo = Foo(42, 66)
>>> print(foo)
Foo(x=42, y=66)

>>> foo2 = Foo("abc", "xyz")
>>> print(foo2)
Foo(x='abc', y='xyz')

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接