可以腌制的动态继承?

时间:2019-12-14 19:53:21

标签: python pickle dill

经过大量搜索,我发现解决我的特定问题的唯一方法是使用动态继承。遵循here的指南和其他一些SO问题非常容易;大多数表是this

使用第一个链接中的人为示例的修改版本:

def makeinst(cls, *args, **kwargs):
    class NewClass(cls): pass
    return NewClass(*args, **kwargs)
mylist = makeinst(list,(1,2))

这如我所愿,但不能腌制:

pickle.dumps(mylist)
...

AttributeError: Can't pickle local object 'makeinst.<locals>.NewClass'

我理解为什么无法正常工作,但是我想知道有解决办法吗?有没有更好的方法可以动态地对某些事物进行子类化?

(FWIW,dill也无法做到。请参见dill issue #56

1 个答案:

答案 0 :(得分:1)

您可以在模块的global范围内创建该类,为此,您需要通过type(name, bases, class_dict)调用手动创建一个类

import pickle

def makeinst(name, cls, *args, **kwargs):

    # This will be a method
    def foo(self):
        return f"I am: {self!r}"

    globals()[name] = type(
        name,
        # This must be a tuple
        # (cls) evaluate to cls
        # (cls,) evaluates to a tuple containing cls as its only element
        (cls,),
        # Methods, classmethods, staticmethods and all class-level data
        {
            "foo": foo
        },
    )

    return globals()[name](*args, **kwargs)

my_list = makeinst("MyList", list, [1, 2, 3])
print(my_list) # [1, 2, 3]

data = pickle.dumps(my_list)
my_list_unpickled = pickle.loads(data)
print(my_list_unpickled) # [1, 2, 3]

print(my_list_unpickled.foo()) # I am: [1, 2, 3]

在另一个程序执行中,必须至少调用makeinst("MyList", list)一次,然后才能取消定义类。