【问题标题】:Pickle a Dynamically Created Mixin-Class腌制一个动态创建的 Mixin 类
【发布时间】:2021-12-18 14:08:24
【问题描述】:

我正在使用 mixins 动态创建类,遵循这个 SO 答案中的模式,但它给了我酸洗错误:

https://stackoverflow.com/a/28205308/2056246

(如果有人好奇我到底为什么要这样做,当您可能想要测试不同的操作组合管道时,它对机器学习非常有用)。

这是一个可重复性最低的示例:

class AutoMixinMeta(ABCMeta):
    """
        Helps us conditionally include Mixins, which is useful if we want to switch between different
        combinations of models (ex. SBERT with Doc Embedding, RoBERTa with positional embeddings).

        class Sub(metaclass = AutoMixinMeta):
            def __init__(self, name):
            self.name = name
    """

    def __call__(cls, *args, **kwargs):
        try:
            mixin = kwargs.pop('mixin')
            if isinstance(mixin, list):
                mixin_names = list(map(lambda x: x.__name__, mixin))
                mixin_name = '.'.join(mixin_names)
                cls_list = tuple(mixin + [cls])
            else:
                mixin_name = mixin.__name__
                cls_list = tuple([mixin, cls])

            name = "{}With{}".format(cls.__name__, mixin_name)
            cls = type(name, cls_list, dict(cls.__dict__))
        except KeyError:
            pass
        return type.__call__(cls, *args, **kwargs)


class Mixer(metaclass = AutoMixinMeta):
    """ Class to mix different elements in.

            a = Mixer(config=config, mixin=[A, B, C])
    """
    pass


class A():
    pass

class B():
    pass

config={
    'test_a': True, 
    'test_b': True
}

def get_mixins(config):
    mixins = []
    if config['test_a']:
        mixins.append(A)
    if config['test_b']:
        mixins.append(B)
    return mixins

to_mix = get_mixins(config)

c = Mixer(mixin=to_mix)

import pickle
pickle.dump(c, open('tmp/test.pkl', 'wb'))
---------------------------------------------------------------------------
PicklingError                             Traceback (most recent call last)
<ipython-input-671-a7661c543ef8> in <module>
     23 
     24 import pickle
---> 25 pickle.dump(c, open('tmp/test.pkl', 'wb'))

PicklingError: Can't pickle <class '__main__.MixerWithA.B'>: attribute lookup MixerWithA.B on __main__ failed

我已经阅读了几个专注于使用__reduce__的答案:

https://stackoverflow.com/a/11526524/2056246 https://stackoverflow.com/a/11493777/2056246 Pickling dynamically created classes

但它们都没有在元类级别处理这种动态创建。

以前有没有人遇到过这个问题/知道如何解决它?不幸的是,我对元类知之甚少,无法理解如何解决这个问题。

【问题讨论】:

    标签: python pickle metaclass


    【解决方案1】:

    现在没有足够的时间来获得完整的答案,使用工作代码 - 但既然你已经有了元类,也许这可以工作 通过简单地在元类本身上实现酸洗协议使用的方法 - __getstate____setstate__。使用基类的__qualname__ 作为字符串元组作为序列化信息,您将需要稍后重新创建腌制类。

    (如果您从现在开始 48 小时以上阅读这篇文章并且还没有示例代码,请在 cmets 中联系我)

    【讨论】:

    • 谢谢@jsbueno。你所说的在高层次上是有道理的,但我有点不清楚——我认为__getstate____setstate__ 是类的属性,而不是元类。理想情况下,我应该更多地了解元类,但我现在面临着论文提交的截止日期压力。
    • 无论如何,我期待代码 - 我已经投票赞成你的答案,我会很快接受它
    • 对不起 - 我昨天摆弄了这个 - 由于它的使用方式有点复杂。可能有一个主要的捷径,thugh:尝试使用外部包“dill”而不是内置的pickle。它应该开箱即用地处理动态类。
    • 抱歉耽搁了——如果我没记错的话,multiprocessing 包在后台使用了pickle,所以我无法控制这个调用
    猜你喜欢
    • 2010-12-29
    • 2011-06-06
    • 1970-01-01
    • 1970-01-01
    • 2015-12-29
    • 2014-04-24
    • 2011-09-29
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多