Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/google-apps-script/6.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 在方法链接期间暂时保留对对象的更改_Python_Class_Oop_Fluent_Fluent Interface - Fatal编程技术网

Python 在方法链接期间暂时保留对对象的更改

Python 在方法链接期间暂时保留对对象的更改,python,class,oop,fluent,fluent-interface,Python,Class,Oop,Fluent,Fluent Interface,我正在设计一个面向对象的数据结构,从用户的角度来看,它应该易于处理,例如,通过方法链接(aka)。但是,每次更改只能临时作用于对象:在该链内,但不能超出该链。 以下是一个无法按预期工作的简化示例: class C: def __init__(self, num): self.sum = num def add(self, num=0): self.sum += num return self number = C(23) num

我正在设计一个面向对象的数据结构,从用户的角度来看,它应该易于处理,例如,通过方法链接(aka)。但是,每次更改只能临时作用于对象:在该链内,但不能超出该链。
以下是一个无法按预期工作的简化示例:

class C:
    def __init__(self, num):
        self.sum = num

    def add(self, num=0):
        self.sum += num
        return self

number = C(23)
number.add(7).add(12).sum
# 42
number.sum
# 42 (but I expect: 23)
在这种情况下,
.add()
对编号进行永久性更改。然而,永久性的改变只能是这样:

# This is the only way how a user should make permanent changes:
number = number.add(4).add(12)
在临时范围内,我正在寻找一种方法,在链终止后返回到旧版本的
number
。在绝望的边缘,我可以想到丑陋的解决方案,如“实例复制”:

然而,我使用的实际类和对象包含大量的数据、属性、方法甚至子类。因此,除了涉及难看的代码之外,我们应该避免在每个方法中复制实例

是否有解决此问题的方法,例如,在链的第一个元素(静默)仅创建一个副本一次?或者通过销毁链末端所做的任何更改?(请注意,现实世界中的“更改”涉及许多不同的、可交换的方法,而不仅仅是添加数字)

可接受的解决方案应在内部执行必要的操作,即不影响用户界面:

# These are NOT accepted solutions:
number.copy().add(4).add(12)
number.add(4).add(12).undo()

如果除了自复制之外没有直接的解决方案,那么问题是:哪种最优雅的方法可以保持代码可读性并保持内存使用率低?例如,通过自复制函数修饰每个类方法?

返回一个修改过的副本,而不是修改调用该方法的对象:

class C:
    def __init__(self, num):
        self.sum = num

    def add(self, num=0):
        return C(self.sum + num)

number = C(23)
assert number.add(7).add(12).sum == 42
assert number.sum == 23

有关此解决方案中内存处理的详细信息,请参阅本文的评论。此解决方案是解决问题的标准方法。

我不认为对象如何能够自动检测“临时作用域”的结尾,除非可能编写自己的基于python的语言,甚至。。。FWIW,到目前为止,我所看到的所有“流畅接口”实现要么原地改变对象,要么返回副本。然后我告诉你,这是标准实践,不是肮脏的黑客行为。我知道这是许多应用程序的标准。但对于大型实例,这也是推荐的(或唯一的)策略吗?我担心这会极大地增加内存使用:或者python会在链终止时自动删除所有实例吗?中间实例将在无法访问时立即从内存中删除。例如,当我们完成调用…add(12)时,结果(sum==42的实例)有一个引用,该引用将用于获取它的sum属性,但number.add(7)的结果将不再可访问,所以它将成为垃圾收集的主题。这并不意味着它将在此时从内存中删除-不保证GC会运行,但在这一点上它被标记为过时。从长远来看,中间链接结果将被丢弃,并且只会在短时间内污染内存;当然,你也可以自己用谷歌搜索一下。如果你需要更多的解释,让我知道,我会尽力帮助你。
class C:
    def __init__(self, num):
        self.sum = num

    def add(self, num=0):
        return C(self.sum + num)

number = C(23)
assert number.add(7).add(12).sum == 42
assert number.sum == 23