无法挑选<class'a =“”class'=“”>:类上的属性查找内部类失败

时间:2018-02-05 03:44:20

标签: python-3.x metaprogramming pickle metaclass

我使用PySpark处理一些调用数据。如您所见,我通过使用元类动态地向类GetInfoFromCalls添加了一些内部类。 下面的代码位于所有节点中存在的包for_test中:

class StatusField(object):
    """
    some alias.
    """
    failed = "failed"
    succeed = "succeed"
    status = "status"
    getNothingDefaultValue = "-999999"


class Result(object):
    """
    Result that store result and some info about it.
    """

    def __init__(self, result, status, message=None):
        self.result = result
        self.status = status
        self.message = message

structureList = [
    ("user_mobile", str, None),
    ("real_name", str, None),
    ("channel_attr", str, None),
    ("channel_src", str, None),
    ("task_data", dict, None),
    ("bill_info", list, "task_data"),
    ("account_info", list, "task_data"),
    ("payment_info", list, "task_data"),
    ("call_info", list, "task_data")
]

def inner_get(self, defaultValue=StatusField.getNothingDefaultValue):
    try:
        return self.holder.get(self)
    except Exception as e:
        return Result(defaultValue, StatusField.failed)
        print(e)

class call_meta(type):
    def __init__(cls, name, bases, attrs):

        for name_str, type_class, pLevel_str in structureList:
            setattr(cls, name_str, type(
                name_str,
                (object,),
                {})
                )

class GetInfoFromCalls(object, metaclass = call_meta):
    def __init__(self, call_deatails):
        for name_str, type_class, pLevel_str in structureList:
            inn = getattr(self.__class__, name_str)()
            object_dict = {
                "name": name_str,
                "type": type_class,
                "pLevel": None if pLevel_str is None else getattr(self, pLevel_str),
                "context": None,
                "get": inner_get,
                "holder": self,
            }
            for attr_str, real_attr in object_dict.items():
                setattr(inn, attr_str, real_attr)
            setattr(self, name_str, inn)

        self.call_details = call_deatails

当我跑

import pickle

pickle.dumps(GetInfoFromCalls("foo"))

它引发了这样的错误:

Traceback (most recent call last):
  File "<ipython-input-11-b2d409e35eb4>", line 1, in <module>
    pickle.dumps(GetInfoFromCalls("foo"))
PicklingError: Can't pickle <class '__main__.user_mobile'>: attribute lookup user_mobile on __main__ failed

似乎我不能腌制内部类,因为它们是通过代码动态添加的。当课程被腌制时,内部课程不存在,是不是? 我真的不想写这些彼此几乎相同的课程。有人有办法避免这个问题吗?

1 个答案:

答案 0 :(得分:2)

Python的pickle实际上没有序列化类:它确实序列化了实例,并在序列化中引入了对每个实例的类的引用 - 并且该引用基于绑定到名称的类的类一个定义良好的模块。因此,没有模块名称,而是作为其他类中的属性或列表和词典中的数据存在的类的实例通常不起作用。

人们可以尝试做的一件事是尝试使用dill而不是泡菜。它是第三方包,其工作方式类似于&#34; pickle&#34;但是有实际序列化任意动态类的扩展。

虽然使用dill可能会帮助其他人到达此处,但事实并非如此,因为为了使用dill,您必须修补PySpark使用的基础RPC机制莳萝而不是泡菜,这可能不是微不足道,也不足以生产使用。

如果问题实际上是关于动态创建的类是不可删除的,那么你可以做的是为动态类本身创建额外的元类,而不是使用&#34; type&#34;,并且在这些元类上,创建正确的__getstate____setstate__(或其他辅助方法,因为它是on pickle documentation) - 这可能使普通的Pickle能够对这些类进行腌制。也就是说,在代码中使用带有Pickler辅助方法的单独元类代替type(..., (object, ), ...)

然而,&#34;不可见的对象&#34;这不是你得到的错误 - 它是一个属性查找错误,它表明你正在构建的结构不足以让Pickle反省并从你的一个实例中获取所有成员 - 它还没有相关性(还)对类对象的不可克服性。由于你的动态类作为类的属性(它本身不是pickle)而不是实例,所以pickle很可能不关心它。检查上面的pickle上的文档,也许你需要的只是正确的帮助方法来挑选你的类,没有什么不同的元类,你可以在那里正常工作。