我的特殊问题是与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
方法。修补save
是patch_save
内部的封闭,因为它使用FieldTracker
中的属性,调用传递的instance
等方法。
FieldTracker
的方法包含闭包,则不能将其作为一个腌制。根据我的尝试,save
无法移动到班级,因为我得到了TypeError: can't pickle instancemethod objects
。当我试图将patch_save
移到顶层时,它会产生与上面代码相同的异常(惊讶,惊讶)。将save
移到顶层可能意味着使用全局变量,我想避免使用它(但我还没有真正尝试过它)。
问题是:是否有可能将FieldTracker
代码重构为pickleable或者我应该使用不同的方法(比如将save
移动到模型mixin)?
This是真实的FieldTracker
。
答案 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帮助您了解代码失败时导致酸洗失败的原因。