Python — укроп: не могу рассолить украшенный класс

У меня есть следующий код, который украшает класс:

import dill
from collections import namedtuple
from multiprocessing import Process

def proxified(to_be_proxied):
    b = namedtuple('d', [])

    class Proxy(to_be_proxied, b):
        pass

    Proxy.__name__ = to_be_proxied.__name__
    return Proxy


@proxified
class MyClass:
    def f(self):
        print('hello!')


pickled_cls = dill.dumps(MyClass)


def new_process(clazz):
    dill.loads(clazz)().f()


p = Process(target=new_process, args=(pickled_cls,))
p.start()
p.join()

Когда я пытаюсь рассолить украшенный класс, я получаю следующую ошибку:

Traceback (most recent call last):
  File "/usr/lib/python3.5/pickle.py", line 907, in save_global
    obj2, parent = _getattribute(module, name)
  File "/usr/lib/python3.5/pickle.py", line 265, in _getattribute
    .format(name, obj))
AttributeError: Can't get local attribute 'proxified.<locals>.Proxy' on <function proxified at 0x7fbf7de4b8c8>

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/home/carbolymer/example.py", line 108, in <module>
    pickled_cls = dill.dumps(MyClass)
  File "/usr/lib/python3.5/site-packages/dill/dill.py", line 243, in dumps
    dump(obj, file, protocol, byref, fmode, recurse)#, strictio)
  File "/usr/lib/python3.5/site-packages/dill/dill.py", line 236, in dump
    pik.dump(obj)
  File "/usr/lib/python3.5/pickle.py", line 408, in dump
    self.save(obj)
  File "/usr/lib/python3.5/pickle.py", line 475, in save
    f(self, obj) # Call unbound method with explicit self
  File "/usr/lib/python3.5/site-packages/dill/dill.py", line 1189, in save_type
    StockPickler.save_global(pickler, obj)
  File "/usr/lib/python3.5/pickle.py", line 911, in save_global
    (obj, module_name, name))
_pickle.PicklingError: Can't pickle <class '__main__.proxified.<locals>.Proxy'>: it's not found as __main__.proxified.<locals>.Proxy

Как я могу замариновать украшенный класс, используя укроп? Я хотел бы передать этот класс отдельному процессу в качестве аргумента - может быть, есть более простой способ сделать это?


person carbolymer    schedule 13.10.2016    source источник
comment
В этом примере происходит много вещей, и многие из них сложны для сериализации. Во-первых, я предлагаю использовать multiprocess вместо multiprocessing, чтобы вы использовали dill, а не pickle. Во-вторых, избегайте namedtuple, если можете. Они сериализуются, но работают только в определенных случаях. В-третьих, по возможности избегайте декоратора класса. Не помню, насколько хорошо dill с ними справляется, думаю, плохо. Наконец, вы можете попробовать разные dill.settings для вариаций таких вещей, как то, как dill обрабатывает глобальные переменные. Для начала используйте multiprocess и не используйте namedtuple.   -  person Mike McKerns    schedule 21.12.2016


Ответы (1)


Хорошее объяснение «Почему травление декорированных функций болезненно», предоставленное Гаэлем Варокво можно найти здесь.

В основном переписывание класса с использованием functools.wraps может избежать этих проблем :)

person Sacha Vakili    schedule 30.01.2017