我的具体问题与 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
是数据库行的表示。 FieldTracker
跟踪 Model
中字段的更改(在本例中为 name_field
)。 FieldTracker
需要在实例化 Model
后修补 save
方法。修补的 save
是 patch_save
内部的闭包,因为它使用 FieldTracker
中的属性,从传递的 instance
等调用方法。
FieldTracker
的方法包含闭包,则无法将其作为一个 pickle。根据我的尝试,save
无法移动到类级别,因为我收到 TypeError: can't pickle instancemethod objects
。当我尝试将 patch_save 移至顶层时,它产生了与上面代码相同的异常(惊讶,惊讶)。将 save
移动到顶层可能意味着使用全局变量,我想避免这种情况(但我实际上还没有尝试过)。
问题是:是否可以将 FieldTracker 代码重构为可pickle,或者我应该使用不同的方法(例如将覆盖的 save
移动到模型 mixin)?
This如果有人关心的话,它是真正的FieldTracker
。
最佳答案
为什么要费力重构?我猜您真的对在编写类和实例时对其进行 pickle 感兴趣,对吧?为此,我将使用 dill ,它几乎可以 pickle 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
迪尔还有some good tools帮助您了解当代码失败时导致 pickle 失败的原因。
关于python - 如何重构返回闭包的方法以使其可 pickle ?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19406097/