一个自定义Python类的__repr__哪个更好?

10

看起来__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++中设置为“private”的内容不会被作为构造函数的参数轻易接受,使用该类的队友必须使用接口函数进行设置,即使这对他们来说更加繁琐。在这种情况下,我将定义一个不接受某些参数的构造函数,并定义一个稍微难以注意到的单独函数,用于__repr__的目的。

如果有所区别,我计划使用它们的__repr__输出将这些Python对象存储在数据库中,并使用eval()检索它们,至少在没有找到更好方法之前是这样的。队友手动创建完整对象而不是通过适当的接口函数进行操作的后果只是一种类型的信息检索可能不稳定,直到有人弄清楚他做了什么。


你可以使用pickle将对象存储到数据库中。 - user780363
@Franklin 谢谢,我会看看Pickle。之前的项目中没有必要进行存储和检索。 - Brian
@pst - 但是它也应该满足 eval(repr(obj)) == obj,对吧? - Brian
2
@Brian 不,这根本不是必需的。虽然基本类型(数字、字符串等)是这样工作的,但行为没有任何约定。请考虑:eval(repr(re.compile("doesn't work"))),其中 re 是正则表达式模块。 - user166390
1
@pst 哦,好的,所以我听说 eval(repr(obj)) == obj 对于更复杂的对象来说不太适用,而可读性和调试是唯一的实际目标。 - Brian
显示剩余2条评论
1个回答

13

__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可以直接使用,但对于更复杂的对象,您可能需要编写自定义程序。

哇,这真是出乎意料的简单。 - Brian
此外,使用的是Python 2.5.2版本。 - Brian
Pickle已经过时了。请参见http://docs.python.org/release/1.4/lib/node31.html#SECTION00440000000000000000。 - Dietrich Epp
既然我们已经在谈论pickle,你说自定义pickler...如果一个自定义类包含另一个自定义类的列表,那么这是其中一种情况吗?鉴于两者都不是非常复杂的,否则只是一些整数和字符串。 - Brian
可能不会。我会使用自定义的pickler来排除缓存值,或者允许pickle那些包含对不应pickle的对象的引用的东西,比如sockets。 - Dietrich Epp

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