如何在python 3.6中动态创建从decorator创建的类

时间:2017-12-21 00:24:25

标签: python pickle python-3.6

声明:

在阅读这篇文章之前,我知道我正在尝试在python中做一些非常规的事情。因为"不做x"不是答案"我该如何做x?"让我们假设有一个很好的理由去做,尽管在大多数情况下这不是一个好习惯。

问题

鉴于我有一个通过将一个装饰器应用于一个函数来动态创建的类,我将如何去挑选一个所述类的实例?

例如,要设置它,它可能如下所示:

import inspect
from functools import wraps 


class BaseClass:
    pass


def _make_method(func):
    """ decorator for adding self as first argument to function """

    @wraps(func)
    def decorator(self, *args, **kwargs):
        return func(*args, **kwargs)

    # set signature to include self
    sig = inspect.signature(decorator)
    par = inspect.Parameter('self', 1)
    new_params = tuple([par] + list(sig.parameters.values()))
    new_sig = sig.replace(parameters=new_params,
                          return_annotation=sig.return_annotation)
    decorator.__signature__ = new_sig
    return decorator


def snake2camel(snake_str):
    """ convert a snake_string to a CamelString """
    return "".join(x.title() for x in snake_str.split('_'))


def make_class(func):
    """ dynamically create a class setting the call method to function """
    name = snake2camel(func.__name__)  # get the name of the new class
    method = _make_method(func)
    cls = type(name, (BaseClass,), {'__call__': method}) 
    return cls()


@make_class
def something(arg):
    return arg

现在有些东西是动态创建的类Something的实例。

type(something)  # -> __main__.Something
isinstance(something, BaseClass)  # -> True

工作正常,但当我尝试腌制它(或使用在引擎盖下使用泡菜的多处理模块)时:

import pickle
pickle.dumps(something)  # -> raises

它会抛出此错误:

# PicklingError: Can't pickle <class '__main__.Something'>: attribute lookup Something on __main__ failed

所以我认为我可以重新定义BaseClass以使用 reduce 方法,如下所示:

class BaseClass:
    def __reduce__(self):
        return make_class, (self.__call__.__func__,)

然后它抛出可怕的&#34;不是同一个对象&#34;错误:

# PicklingError: Can't pickle <function something at 0x7fe124cb2d08>: it's not the same object as __main__.something

如何在不引入依赖关系的情况下完成此工作?我需要能够挑选something对象,这样我就可以使用python 3.6中concurrent.futures模块的ProcessPoolExecutor类,所以简单地使用dill或cloudpickle可能不是一个选项。

0 个答案:

没有答案