自定义Python类哪个__repr__更好?

11 投票
1 回答
6377 浏览
提问于 2025-04-16 19:35

看起来,__repr__ 函数可以有不同的返回方式。

我有一个叫做 InfoObj 的类,它存储了很多东西,其中一些我并不希望用户自己设置。我知道在 Python 中没有什么是受保护的,他们可以随便修改,但我觉得在 __init__ 中定义这些属性会让人更容易看到,并认为可以直接传入。

(举个例子:一些布尔值是通过验证函数设置的,当它确定对象已经完全填充时;还有一些值是根据其他值计算出来的,当存储的信息足够时... 比如 A = B + C,所以一旦 A 和 B 被设置,C 就会被计算出来,并且对象会标记为 Valid=True。)

所以,考虑到这些,__repr__ 的输出应该怎么设计才好呢?

    bob = InfoObj(Name="Bob")
    # Populate bob.

    # Output type A:
    bob.__repr__()
'<InfoObj object at 0x1b91ca42>'

    # Output type B:
    bob.__repr__()
'InfoObj(Name="Bob",Pants=True,A=7,B=5,C=2,Valid=True)'

    # Output type C:
    bob.__repr__()
'InfoObj.NewInfoObj(Name="Bob",Pants=True,A=7,B=5,C=2,Valid=True)'

... 在类型 C 的设计中,我的目的是不让它轻易接受我在 C++ 中设置为“私有”的那些东西作为构造函数的参数,并让使用这个类的队友通过接口函数来设置这些属性,尽管这对他们来说可能更麻烦。在这种情况下,我会定义一个构造函数,不接受某些参数,并提供一个稍微不那么显眼的单独函数,用于 __repr__

如果有影响的话,我打算把这些 Python 对象存储在数据库中,使用它们的 __repr__ 输出,并通过 eval() 来检索,至少在我找到更好的方法之前。队友手动创建完整对象而不是通过正确的接口函数来做,可能导致某种信息检索不稳定,直到有人弄清楚他做了什么。

1 个回答

14

这个 __repr__ 方法是为了给开发者提供最有用的信息,而不是给最终用户看的,所以只有你自己才能真正回答这个问题。不过,我通常会选择选项B。选项A不太有用,而选项C则显得有点啰嗦——反正你也不知道你的模块是怎么被导入的。其他人可能会更喜欢选项C。

不过,如果你想把Python对象存储到数据库里,可以使用 pickle

import pickle
bob = InfoObj(Name="Bob")

> pickle.dumps(bob)
b'...some bytestring representation of Bob...'

> pickle.loads(pickle.dumps(bob))
Bob(...)

如果你在用老版本的Python(3.x之前),那么要注意 cPickle 速度更快,但 pickle 更灵活。Pickle可以在一些类上直接使用而不需要配置,但对于更复杂的对象,你可能需要写一些自定义的序列化代码。

撰写回答