通过重新加载另一个函数来选择多处理函数

Pickle a function for multiprocessing by making it reload another

假设我有以下简单的 class:

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

然后我可以将 HelloWorld.call 与多处理一起使用,尽管 python 知道如何 pickle HelloWorld.call。但是,假设我想将该函数包装在 metaclass,

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 用于多处理,因为它不会 pickle。我想要的是 python 不使用包装函数进行 pickling,而是使用原始函数(尽管在 unpickling 之后它会默认引用包装函数)。

有什么建议吗?谢谢!

查看源码,可以看到ForkingPicklermultiprocessing的自定义Pickler)通过__func__-属性的[=15=方法pickles ].所以我要做的就是将 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__。也可以。