选择一个动态参数化的子类 [英] Pickle a dynamically parameterized sub-class

查看:150
本文介绍了选择一个动态参数化的子类的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个通常存储pickled类类型的系统。

I have a system which commonly stores pickled class types.

我想以同样的方式保存动态参数化的类,但是我不能因为我得到一个PicklingError试图选择一个不是全局找到的类(未定义在简单的代码)。

I want to be able to save dynamically-parameterized classes in the same way, but I can't because I get a PicklingError on trying to pickle a class which is not globally found (not defined in simple code).

我的问题可以建模为以下示例代码:

My problem can be modeled as the following example code:

class Base(object):
 def m(self):
  return self.__class__.PARAM

def make_parameterized(param_value):
 class AutoSubClass(Base):
  PARAM = param_value
 return AutoSubClass

cls = make_parameterized(input("param value?"))



当我尝试pickle类时,我得到以下错误:

When I try to pickle the class, I get the following error:

# pickle.PicklingError: Can't pickle <class '__main__.AutoSubClass'>: it's not found as __main__.AutoSubClass
import pickle
print pickle.dumps(cls)

寻找一些方法来声明Base作为 ParameterizableBaseClass ,它应该定义所需的参数(在上面的例子中 PARAM )。然后可以通过保存ParameterizableBaseClass类型和不同的参数值(动态 param_value cls c $ c>上面)。

I am looking for some method to declare Base as a ParameterizableBaseClass which should define the params needed (PARAM in above example). A dynamic parameterized subclass (cls above) should then be picklable by saving the "ParameterizableBaseClass" type and the different param-values (dynamic param_value above).

我相信在许多情况下,这可以完全避免...我可以避免在我的代码,真的(真的)有。我正在玩 __ metaclass __ copyreg ,甚至 __ builtin __。issubclass 在某些时候(不要问),但是无法破解这个。

I am sure that in many cases, this can be avoided altogether... And I can avoid this in my code as well if I really (really) have to. I was playing with __metaclass__, copyreg and even __builtin__.issubclass at some point (don't ask), but was unable to crack this one.

我觉得我不会真的对python精神,如果我wasn

I feel like I wouldn't be true to the python spirit if I wasn't to ask: how can this be achieved, in a relatively clean way?

推荐答案

是的,这是可能的 -

Yes, it is possible -

每当你想为你的对象定制Pickle和Unpickle行为时,你只需要设置 __ getstate __ __ setstate __ 类本身的方法。

Whenever you want to custom the Pickle and Unpickle behaviors for your objects, you just have to set the "__getstate__" and "__setstate__" methods on the class itself.

在这种情况下有点棘手:
正如你所观察到的,需要在全局命名空间上存在一个类,它是当前被pickled对象的类:它必须是同一个类,具有相同的名称。 Ok - 这个协议是在全局名空间中存在的gthis类可以在Pickle时间创建。

In this case it is a bit trickier: There need, as you observed - to exist a class on the global namespace that is the class of the currently being pickled object: it has to be the same class, with the same name. Ok - the deal is that gthis class existing in the globalname space can be created at Pickle time.

在Unpickle时间,同名的类必须存在 - 但它不必是相同的对象 - 只是表现得像它一样 - 并且在Unpickling进程中调用 __ setstate __ ,它可以重新创建orignal对象的参数化类,并通过设置对象的 __ class __ 属性来设置自己的类。

At Unpickle time the class, with the same name, have to exist - but it does not have to be the same object - just behave like it does - and as __setstate__ is called in the Unpickling proccess, it can recreate the parameterized class of the orignal object, and set its own class to be that one, by setting the __class__ attribute of the object.

__ class __ 对象的属性可能看起来令人反感,但它是如何在Python中工作,它是正式记录,它甚至工作在实施。 (我在Python 2.6和Pypy中测试过这个片段)

Setting the __class__ attribute of an object may seen objectionable but it is how OO works in Python and it is officially documented, it even works accross implementations. (I tested this snippet in both Python 2.6 and Pypy)

class Base(object):
    def m(self):
        return self.__class__.PARAM
    def __getstate__(self):
        global AutoSub
        AutoSub = self.__class__
        return (self.__dict__,self.__class__.PARAM)
    def __setstate__(self, state):
        self.__class__ = make_parameterized(state[1])
        self.__dict__.update(state[0])

def make_parameterized(param_value):
    class AutoSub(Base):
        PARAM = param_value
    return AutoSub

class AutoSub(Base):
    pass


if __name__ == "__main__":

    from pickle import dumps, loads

    a = make_parameterized("a")()
    b = make_parameterized("b")()

    print a.PARAM, b.PARAM, type(a) is type(b)
    a_p = dumps(a)
    b_p = dumps(b)

    del a, b
    a = loads(a_p)
    b = loads(b_p)

    print a.PARAM, b.PARAM, type(a) is type(b)

这篇关于选择一个动态参数化的子类的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆