首页 > 解决方案 > 通过使其重新加载另一个函数来腌制一个用于多处理的函数

问题描述

假设我有以下简单的类:

class HelloWorld:
   def call(self):
       print('Hello World!')

然后我可以使用HelloWorld.callwith multiprocessing 虽然 python 知道如何 pickle HelloWorld.call。但是,假设我想将该函数包装在一个元类中,

class MetaClass(type):
    def __new__(mcs, name, bases, dct):

        def wrap(f):
            def wrapper(self):
                print(f.__qualname__)
                f(self)

            return wrapper

        new_dct = dict()
        for attr_name in dct.keys():
            if callable(dct[attr_name]):
                new_dct[attr_name] = wrap(dct[attr_name])
            else:
                new_dct[attr_name] = dct[attr_name]

        return type.__new__(mcs, name, bases, new_dct)

class HelloWorld(metaclass=MetaClass):
   def call(self):
       print('Hello World!')

然后我不能使用HelloWorld.call多处理,因为它不会腌制。我想要的是使python不使用包装函数进行酸洗,而是使用原始函数(尽管在取消酸洗后它将默认引用包装函数)。

有什么建议么?谢谢!

标签: pythonpython-3.xpicklepython-multiprocessingmetaclass

解决方案


查看源代码,您可以看到ForkingPickler( multiprocessing's custom Pickler) 通过方法__func__-attribute's腌制__name__。所以我要做的就是设置wrapper.__name__与原始成员的名称相同:

class MetaClass(type):
    def __new__(mcs, name, bases, dct):

        def wrap(f):
            def wrapper(self):
                print(f.__qualname__)
                f(self)

            #############################
            wrapper.__name__ = f.__name__
            #############################

            return wrapper

        new_dct = dict()
        for attr_name in dct.keys():
            if callable(dct[attr_name]):
                new_dct[attr_name] = wrap(dct[attr_name])
            else:
                new_dct[attr_name] = dct[attr_name]

        return type.__new__(mcs, name, bases, new_dct)

class HelloWorld(metaclass=MetaClass):
   def call(self):
       print('Hello World!')

也可以使用functools.update_wrapper(wrapper, f)而不仅仅是设置__name__。也会起作用。


推荐阅读