【问题标题】:Dynamic inheritance that is pickleable?可腌制的动态继承?
【发布时间】:2019-12-14 19:53:21
【问题描述】:

经过大量搜索,我发现解决我的特定问题的唯一方法是使用动态继承。遵循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

【问题讨论】:

    标签: python pickle dill


    【解决方案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),然后才能取消腌制以定义类。

    【讨论】:

    • 这确实符合我的要求(谢谢!),但我应该添加一个额外的要求(对不起,我没有想到)。此解决方案不适用于跨会话。因此,如果我保存泡菜然后重新加载它而不调用每个makeinst("MyList",...),它就会失败。有什么办法吗? (没有希望......)
    • 我认为这是不可能的,至少对于当前的泡菜实现而言。要重建实例,它调用类的__new__ 方法并按名称查找类。您可以自定义它如何发现状态以及传递给__new__ 的内容,但不能自定义发现类的方式。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-11-25
    • 1970-01-01
    • 2018-03-10
    • 2014-01-30
    • 1970-01-01
    相关资源
    最近更新 更多