我正在试图找出如何使用Pickle
将对象序列化为保存文件。我的示例是一个名为World
的对象,该对象有一个list
(名为objects
)可能有数百个不同类类型的实例化对象。
问题是Pickle
不允许我序列化World.objects
列表中的项目,因为它们未被实例化为World
的属性。
当我尝试序列化时:
with open('gsave.pkl', 'wb') as output:
pickle.dump(world.objects, output, pickle.DEFAULT_PROTOCOL)
我收到以下错误:
_pickle.PicklingError: Can't pickle <class 'world.LargeHealthPotion'>:
attribute lookup LargeHealthPotion on world failed
所以,我的问题是:什么是存储world.objects
列表项的替代方法,以便它们是world
的属性而不是列出未保存的项目?
更新
我认为我的问题不在于存储对象的位置;而是通过以下操作在LargeHealthPotion
类中动态创建类World
(和许多其他类):
def __constructor__(self, n, cl, d, c, h, l):
# initialize super of class type
super(self.__class__, self).__init__(name=n, classtype=cl, description=d, cost=c,
hp=h, level=l)
# create the object class dynamically, utilizing __constructor__ for __init__ method
item = type(item_name,
(eval("{}.{}".format(name,row[1].value)),),
{'__init__':__constructor__})
# add new object to the global _objects object to be used throughout the world
self._objects[item_name] = item(obj_name, obj_classtype, obj_description, obj_cost,
obj_hp, obj_level)
完成后,我会有一个像<world.LargeHealthPotion object at 0x103690ac8>
这样的新对象。我动态地这样做是因为我不想明确地为我的世界中的每种不同类型的对象创建数百种不同类型的类。相反,我在迭代我想要创建的项目名称(带有它的统计数据)时动态创建类。
这引入了一个问题,因为在进行酸洗时,它无法找到对类的静态引用,以便解构或重构对象......所以它失败了。
我还能做什么? (除了为每个我想要实例化到我的世界的对象类型创建文字类引用。)
答案 0 :(得分:2)
Pickle并不挑选类,它依赖于对类动态生成时不起作用的类的引用。 (this answer具有来自documentation)
的适当施加和粗体所以pickle假设如果你的对象是来自名为world.LargeHealthPotion
的类,那么它会检查该名称是否实际上解析为在解开时它能够使用的类,如果它不是你的话由于它不知道如何引用该类,因此无法重新初始化该对象。有几种方法可以解决这个问题:
__reduce__
以重建对象我不确定如何向您演示此方法,我需要有关您的设置的更多信息,以建议如何实现此方法,但我可以对其进行描述:
首先,您要创建一个函数或classmethod
,它可以根据参数重新创建一个对象(可能需要使用类名,实例变量等)。然后在对象基类上定义__reduce__
这将返回该函数以及unpickling时传递给它所需的参数。
这是快速而肮脏的解决方案。假设类名与world
模块中定义的其他内容不冲突,理论上可以通过globals()[item_name] = item_type
将类插入全局范围,但我不建议将其作为长期解决方案,因为它是非常糟糕的做法。
这绝对是我认为的方式,而不是使用type
构造函数,只需定义一个名为ObjectType
的类:
type
的子类,因此实例可以腌制。假设您有一个名为GameObject
的班级,需要cls=<ObjectType object>
,您可以设置ObjectType
类,如下所示:
class ObjectType:
def __init__(self, name, description):
self.item_name = name
self.base_item_description = description
#other qualities common to all objects of this type
def __call__(self, cost, level, hp):
#other qualities that are specific to each item
return GameObject(cls=self, cost=cost, level=level, hp=hp)
这里我使用__call__
magic method所以它使用与类cls(params)
相同的表示法来创建实例,cls=self
将指示(抽象的)GameObject
构造函数GameObject
的类(类型)基于ObjectType
实例self
。它不一定是关键字参数,但我不确定如何在不了解您的程序的情况下制作连贯的示例代码。