是否可以基于__init__函数改进__repr__的默认实现?

时间:2019-01-11 15:30:48

标签: python

根据我的理解,__repr__用于表示对象的开发人员/解释员友好表示,并且应该是有效的python代码,当传递给eval()时会重新创建相同的对象。

来自Python文档:

  

对象。代表(自己)

     

由repr()内置函数和字符串转换(反引号)调用以计算对象的“正式”字符串表示形式。如果可能的话,这应该看起来像一个有效的Python表达式,可以用来重新创建具有相同值的对象(在适当的环境下)。如果这不可能,则应返回格式为<...一些有用的说明...>的字符串。返回值必须是一个字符串对象。如果一个类定义了 repr ()但没有定义 str (),则当实例的“非正式”字符串表示形式也使用 repr ()该类的人是必需的。

链接:https://docs.python.org/2/reference/datamodel.html#object.repr

例如:

class tie(object):
    def __init__(self, color):
        self.color = color
t = tie('green')
repr(t) # prints <tie object at 0x10fdc4c10>

# can the default implementation be improved to tie(color='green')
# based on the parameters passed in the __init__ function

除了向后兼容性/现有行为之外,改变实施方式还会遇到什么挑战?

2 个答案:

答案 0 :(得分:4)

根据对象的创建方式进行默认repr会带来效率低下和混乱的情况

大小

__init__参数必须通过复制存储在对象中的某个位置,这会使对象膨胀。

并非所有对象都简单地将这些值复制到自身中

例如:

class GreedyMan:
    def __init__(self, coins):
        self.most_valuable_coin = max(coins)

您必须将整个硬币收藏保存在这里

类是可变的

使用0xff00ff初始化的Color类可以在其生命周期内更改为另一种颜色

class Color:
    def __init__(self, color):
        self.color = color

    def dilute(self, factor):
        self.color = self.color * factor

dilute可以更改类的状态,因此您将不再具有0xff00ff的颜色,而是具有其他颜色,并且如果出现了诸如“我不接受非红色-提供的Color('red ')“程序员将需要进行一些调试,直到他注意到有人使用dilute来获得一些奇怪的阴影。

那为什么不打印整个状态-所有的类属性

结果可能是巨大的/无限的

图可以具有包含其他节点甚至循环的节点

class ChainPart:
    def __init__(self, parent):
        self.parent = parent
        self.children = []

    def add_child(self, child):
        self.children.append(child)

a=ChainPart(None)
b=ChainPart(a)
b.add_child(a)

以递归方式打印出链部分b及其所有内容后,将不得不打印a部分,而该部分将打印部分b ...等无限制

因此解决这些问题的最明显方法是简化repr并允许程序员使用对象类中的自定义__repr__方法对其进行更改。

答案 1 :(得分:1)

这实际上是pickle试图做的。这个想法是因为内存中的对象是一个图形,所以如果您重新访问该图形,就可以重建该对象。

Pickle生成了一系列指令来重建数据,但原则上可以直接生成Python代码。

尽管我将考虑所有问题,但酸洗在系统需要将数据从一个进程传输到另一个进程的分布式应用中非常广泛地使用。

当您希望能够通过复制并粘贴到提示中来重建对象时,__repr__方法在调试中非常方便。

让我们看看酸洗不起作用的地方:

  1. 某些对象实际上代表对象!例如,网络套接字标识管理实际网络连接的内核资源。即使您可以重新创建它们,也不会再有其他机器在监听。

  2. 某些对象具有现实世界的后果。一个对象可能代表一个不应离开进程内存的密码或其他机密,例如通过打印到日志。

  3. 要确定首先要构建的对象,您必须执行topological sort,并且尽管存在快速算法,但它们并不是免费的。尤其是在发生这种情况时,如果另一个线程修改了图形,事情就会变得繁琐。

  4. 如果您保存此数据并尝试将其重新加载到另一个版本上,它将失败。如果您设计新版本以接受旧数据,则由于代码变得更加扭曲以处理向后兼容性,因此开发速度会缓慢下降。

  5. 它与您的对象和Python的对象模型紧密相关,因此您可以重新实现它。

  6. 它可以访问Python中的所有内容,因此,如果有人通过shutil.rmtree('/'),机器将如实地执行它。

其中大多数都不是制止器,但要进行修复需要权衡。内置__repr__如此之少的主要原因是为了确保简单的事情保持简单。

attrs这样的模块(它启发了python 3.7中的dataclasses模块)提供了一个固定的__repr__罐头,可以满足您的要求并回答大多数用例我想你在想像。

我正在使用一种能够解决其中一些问题的语言,并且我总结了some of the different existing approaches以解决上面提到的问题。