1

我的特殊问题与 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的字段更改。实例化后需要修补方法。Patched是内部的闭包,因为它使用来自的属性,调用来自传递的方法等。Modelname_fieldFieldTrackersaveModelsavepatch_saveFieldTrackerinstance

FieldTracker如果其方法包含闭包,则不能被腌制为一种。根据我的尝试,我save无法将其移至班级级别TypeError: can't pickle instancemethod objects。当我试图移动patch_save到顶层时,它产生了与上面代码相​​同的异常(惊喜,惊喜)。移动save到顶层可能意味着使用全局变量,这是我想避免的(但我实际上并没有尝试过)。

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

FieldTracker如果有人在乎,是真实的。

4

1 回答 1

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 还提供了一些很好的工具,可以帮助您了解在代码失败时导致酸洗失败的原因。

于 2013-10-19T19:35:11.163 回答