我正在使用 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
我似乎无法 pickle 内部类,因为它们是通过代码动态添加的。当类被 pickle 时,内部类不存在,对吗?
真的,我不想编写这些彼此几乎相同的类。有人有避免这个问题的好方法吗?
最佳答案
Python 的 pickle 实际上不序列化类:它序列化实例,并在序列化中放入对每个实例类的引用 - 并且该引用基于绑定(bind)到定义良好的模块中的名称的类。因此,没有模块名称但作为其他类中的属性或列表和字典中的数据存在的类的实例通常不起作用。
可以尝试做的一件直接的事情就是尝试使用 dill
而不是 pickle 。它是一个第三方包,工作方式类似于“pickle”,但具有实际序列化任意动态类的扩展。
虽然使用 dill
可能会帮助其他人到达这里,但这不是你的情况,因为为了使用 dill,你必须猴子修补 PySpark 正在使用的底层 RPC 机制以利用莳萝而不是 pickle ,这对于生产使用来说可能不够微不足道或不够一致。
如果问题真的是动态创建的类是不可拾取的,你可以做的是为动态类本身创建额外的元类,而不是使用“类型”,并在这些元类上创建适当的 __getstate__
和 __setstate__
(或其他辅助方法 on pickle documentation )——这可能使这些类能够被普通的 Pickle pickle 。也就是说,在您的代码中使用带有 Pickler 辅助方法的单独元类代替 type(..., (object, ), ...)
。
但是,“unpickable object”不是您得到的错误 - 它是一个属性查找错误,这表明您正在构建的结构不足以让 Pickle 对其进行内省(introspection)并从您的其中一个获取所有成员instances - 它与类对象的 unpickleability 无关(还)。由于您的动态类作为类的属性存在(它本身不是 pickle 的)而不是实例的属性,因此 pickle 很可能不关心它。检查上面关于 pickle 的文档,也许你只需要有适当的辅助方法来对你的类进行 pickle,元类上没有什么不同,因为你在那里可以正常工作。
关于python-3.x - 无法 pickle <class 'a class' > : attribute lookup inner class on a class failed,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48615601/