Suppose I have the following simple class:
class HelloWorld:
def call(self):
print('Hello World!')
Then I can use the HelloWorld.call
with multiprocessing though python knows how to pickle HelloWorld.call
. However, say I want to wrap that function in a 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!')
Then I can not use HelloWorld.call
with multiprocessing, as it will not pickle. What I want is to cause python not use the wrapper-function for pickling, but rather the original function (though after unpickling it will refer to the wrapped function by default).
Any suggestions? Thanks!
Looking at the source code, you can see that ForkingPickler
(multiprocessing
's custom Pickler
) pickles by the method __func__
-attribute's __name__
. So what I had to do is to set wrapper.__name__
to be the same as the original member's 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!')
One could also use functools.update_wrapper(wrapper, f)
instead of just setting __name__
. Will also work.