首页 > 解决方案 > 腌制部分类

问题描述

我需要部分实例化一个类,然后在多处理中使用。多处理泡菜类在进程之间传递。如何腌制部分实例化的类?

我的目标是 Python 3.8+

PS这是我的partialclass实现:

def partialclass(cls, *args, **kwargs):
    new_cls = type(cls.__name__, (cls,), {})
    new_cls.__init__ = partialmethod(cls.__init__, *args, **kwargs)

    return new_cls

编辑:我考虑过覆盖__reduce__方法,但类可能会接受参数,我在定义时不知道。

标签: python

解决方案


您正在创建一个,而不是“部分实例”。Pickle 不序列化类,因为它假定所有代码都可以从源代码加载。

相反,生成一个实用程序类的实例,一个可以腌制的实例,并且在调用时与调用生成的类执行相同的操作:

class Partial:
    def __init__(self, cls, *args, **kwargs):
        self.cls, self.args, self.kwargs = cls, args, kwargs

    def __call__(self, *args, **kwargs):
        return self.cls(*self.args, *args, **self.kwargs, **kwargs)

然后对类属性进行腌制(这里是对类对象、元组和字典的引用),您可以调用实例来生成实际的类:

>>> import pickle
>>> class Foo:
...     def __init__(self, *args, **kwargs):
...         self.a, self.k = args, kwargs
...     def __repr__(self):
...         return f"<Foo(*{self.a!r}, **{self.k!r})>"
...
>>> pickled = pickle.dumps(Partial(Foo, "bar", monty="python"))
>>> partial = pickle.loads(pickled)
>>> partial("baz", spam="ham")
<Foo(*('bar', 'baz'), **{'monty': 'python', 'spam': 'ham'})>

但是,上面基本上是重新发明functools.partial()object,它们是可以腌制和调用的实用程序类的实例,就像上面的 Python 重新实现一样:

>>> import pickle
>>> from functools import partial
>>> pickled = pickle.dumps(partial(Foo, "bar", monty="python"))
>>> fpartial = pickle.loads(pickled)
>>> fpartial("baz", spam="ham")
<Foo(*('bar', 'baz'), **{'monty': 'python', 'spam': 'ham'})>

functools.partial()但是,内存效率更高,速度更快。

唯一可能的优势是您可以使用isinstance(object, Partial)它与functools.partial(). 但是您也可以为此使用子类化:

import functools

class CPartial(functools.partial): pass

它的工作原理是一样的。


推荐阅读