I am trying to update a class that is supposed to be used as a custom type for the multiprocessing.manager
and imitate a basic dictionary. All works well on Linux, but things fail on Windows and I understood that the problem lies in a possibly suboptimal creation mechanism that it uses that involves a closure. With forking, Linux gets around serializing something that pickle
cannot cope with, while this does not happen on Windows. I am using Python 3.6 and feel like it is better to improve the class rather than force a new package dependency that has more robust serialization than pickle
.
An example that I think demonstrates this is presented below. It involves a class that is meant to act like a dict
, but have an additional method and a class attribute. These are bound in a factory method that the code calls and passes to multiprocessing.manager.register
. I get AttributeError: Can't pickle local object 'foo_factory.<locals>.Foo'
as a result here.
import abc
import pickle
class FooTemplate(abc.ABC, dict):
bar = None
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.foo = 'foo'
@abc.abstractmethod
def special_method(self, arg1, arg2):
pass
def foo_factory(dynamic_special_method):
class Foo(FooTemplate):
bar = 'bar'
def special_method(self, arg1, arg2):
print(self.foo, ' ', self.bar, ' ', dynamic_special_method(arg1, arg2))
return Foo
def method_to_pass(a1, a2):
return a1 + a2
if __name__ == '__main__':
foo = foo_factory(method_to_pass)()
pickle.dumps(foo)
I attempted to fix the problem by creating a class dynamically, but this throws a new error that I am not sure I understand and it makes things look even worse with all honesty. Using the main
part from above with the code below produces error _pickle.PicklingError: Can't pickle <class '__main__.Foo'>: attribute lookup Foo on __main__ failed
.
class FooTemplate(dict):
bar = None
method_map = None
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.foo = 'foo'
def special_method(self, arg1, arg2):
print(self.foo, ' ', self.bar, ' ', self.method_map[self.bar](arg1, arg2))
def foo_factory(dynamic_special_method):
return type('Foo', (FooTemplate,), {'bar': 'bar', 'method_map': {'bar': dynamic_special_method}})
Error above aside, I feel like I am missing something fundamental and that I took a wrong direction. Even if this worked, it feels wrong to introduce a new attribute with a nested structure to simply keep a method which avoids calls to this method as a class method with self
in the front...
Maybe someone can suggest a better direction how to create a preferably serializable class which imitates a dictionary and that can also get parameters dynamically? An explanation of the error that I get would be very useful too, but I think this is not the biggest problem I am facing here. Thank you for any help in advance.