我已经实现了工厂方法模式来参数化产品类的基类:
def factory(ParentClass):
class Wrapper(ParentClass):
_attr = "foo"
def wrapped_method():
"Do things to be done in `ParentClass`."""
return _attr
return Wrapper
我需要通过Wrapper
与使用multiprocessing
模块生成的流程共享multiprocessing.Queue
个对象。
由于multiprocessing.Queue
使用Pickle
来存储对象(请参阅Pickle documentation处的注释),并且Wrapper
未在顶层定义,因此出现以下错误:
PicklingError: Can't pickle <class 'Wrapper'>: attribute lookup Wrapper failed
我使用了此answer中的解决方法,我收到了另一个错误:
AttributeError: ("type object 'ParentClass' has no attribute 'Wrapper'", <main._NestedClassGetter object at 0x8c7fe4c>, (<class 'ParentClass'>, 'Wrapper'))
是否有解决方案在进程间共享这些对象?
答案 0 :(得分:1)
根据Pickle documentation,问题中链接的解决方法可以修改为:
class _NestedClassGetter(object):
"""
From: http://stackoverflow.com/a/11493777/741316
When called with the containing class as the first argument,
and the name of the nested class as the second argument,
returns an instance of the nested class.
"""
def __call__(self, factory_method, base):
nested_class = factory_method(base)
# make an instance of a simple object (this one will do), for which we
# can change the __class__ later on.
nested_instance = _NestedClassGetter()
# set the class of the instance, the __init__ will never be called on
# the class but the original state will be set later on by pickle.
nested_instance.__class__ = nested_class
return nested_instance
和__reduce__
方法:
def __reduce__(self):
state = self.__dict__.copy()
return (_NestedClassGetter(),
(factory, ParentClass), state,)
感谢@dano的评论。
答案 1 :(得分:1)
最好的解决方案是将代码重组为不具有动态声明的类,但假设情况并非如此,那么您可以做更多的工作来腌制它们。
此方法适用于Wrapper
类:
def __reduce__(self):
r = super(Wrapper, self).__reduce__()
return (wrapper_unpickler,
((factory, ParentClass, r[0]) + r[1][1:])) + r[2:]
将此功能添加到您的模块:
def wrapper_unpickler(factory, cls, reconstructor, *args):
return reconstructor(*((factory(cls),) + args))
基本上,你在pickle时交换动态生成的Wrapper
类for factory funciton + wrapped class,然后在unpickling时,再次动态生成Wrapper
类(将包装类型传递给工厂) )并交换Wrapper
的包装类。