如何重构闭包的方法是pickleable?

时间:2013-10-16 14:27:48

标签: python pickle

我的特殊问题是与Django相关,但我将相关代码重写为通用Python以便更好地理解。

import pickle


class FieldTracker(object):
    def patch_save(self, instance):
        original_save = instance.save

        def save(**kwargs):
            ret = original_save(**kwargs)

            # use properties of self, implement new stuff etc
            print 'Used patched save'

            return ret

        instance.save = save


class Model(object):
    name_field = 'joe'

    field_tracker = FieldTracker()

    def __init__(self):
        self.field_tracker.patch_save(self)

    def save(self):
        print 'Used default save'

model = Model()
model.save()  # Uses patched version of save

pickle.dumps(model)  # Fails

Model表示DB行。 FieldTracker跟踪Model中字段的更改(本例中为name_field)。在FieldTracker实例化后,save需要修补Model方法。修补savepatch_save内部的封闭,因为它使用FieldTracker中的属性,调用传递的instance等方法。

如果

FieldTracker的方法包含闭包,则不能将其作为一个腌制。根据我的尝试,save无法移动到班级,因为我得到了TypeError: can't pickle instancemethod objects。当我试图将patch_save移到顶层时,它会产生与上面代码相​​同的异常(惊讶,惊讶)。将save移到顶层可能意味着使用全局变量,我想避免使用它(但我还没有真正尝试过它)。

问题是:是否有可能将FieldTracker代码重构为pickleable或者我应该使用不同的方法(比如将save移动到模型mixin)?

如果有人关心,

This是真实的FieldTracker

1 个答案:

答案 0 :(得分:1)

为什么要重构?我猜你真的有兴趣在编写它们时挑选类和实例,对吗?要做到这一点,我会使用dill,它可以在python中腌制几乎任何东西。

>>> import dill 
>>> class FieldTracker(object):
...   def patch_save(self, instance):
...     original_save = instance.save
...     def save(**kwargs):
...       ret = original_save(**kwargs)
...       print("Used patched save")
...       return ret
...     instance.save = save
... 
>>> class Model(object):
...   name_field = 'joe'
...   field_tracker = FieldTracker()
...   def __init__(self):
...     self.field_tracker.patch_save(self)
...   def save(self):
...     print("Used default save")
... 
>>> model = Model()
>>> model.save()
Used default save
Used patched save
>>> _model = dill.loads(dill.dumps(model))
>>> _model.save()
Used default save
Used patched save

Dill还有some good tools帮助您了解代码失败时导致酸洗失败的原因。

相关问题