可腌制的动态继承?

Dynamic inheritance that is pickleable?

经过多次搜索,我发现解决我的特定问题的唯一方法是使用动态继承。遵循 here and a few other SO questions; most table is this.

中的指南非常简单

使用第一个 link 中 设计的 示例的修改版本:

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

您可以在模块的 global 范围内创建 class,为此您需要使用 type(name, bases, class_dict) 调用手动创建 class

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) 才能定义 class。