如何对Suds的结果进行腌制?

9
为了避免在开发过程中反复访问SOAP服务器,我尝试缓存结果,以便在不每次查询服务器的情况下运行我的其余代码。
使用下面的代码时,当我尝试对suds结果进行 pickling 时,会出现 "PicklingError: Can't pickle <class suds.sudsobject.AdvertiserSearchResponse at 0x03424060>: it's not found as suds.sudsobject.AdvertiserSearchResponse"。我猜这是因为类是动态创建的。
import pickle
from suds.client import Client

client = Client(...)
result = client.service.search(...)

file = open('test_pickle.dat', 'wb')
pickle.dump(result, file, -1)
file.close()

如果我从 pickle.dump(result, file, -1) 中删除 -1 协议版本,我会得到不同的错误:
TypeError: a class that defines __slots__ without defining __getstate__ cannot be pickled

腌制是正确的做法吗?我能做到吗?有更好的方法吗?

2个回答

9

当前错误信息提示您,您正在尝试pickle实例,但这些实例在古老的pickle协议中是不可picklable的,因为它们的类定义了__slots__但没有__getstate__方法。

然而,即使改变它们的类也没有帮助,因为接下来你会遇到另一个问题——你已经正确地确认可能由于动态生成的类。所有pickle协议都通过名称序列化类(和函数),基本上将它们限制在其模块中的顶级名称。而且,序列化实例绝对需要序列化类(如果没有类,你怎么可能在以后重建实例呢?!)。

因此,您需要以其他方式保存和重新加载数据,打破您当前在suds.sudsobject中具体类的直接依赖,而是依赖于一个接口(无论是正式化还是通过鸭子类型定义),该接口可以由这样的具体类实现当您实际访问SOAP服务器时,或者当您从文件加载数据时使用更简单的“自制”类。(表示实例状态的数据可以表示为字典,因此如果您确实想要,您可以通过pickle强制执行它,例如通过copy_reg模块,该模块允许您为您被迫以非侵入方式处理的对象自定义序列化/反序列化协议[[因此您无法绕过向它们的类添加__getstate__或类似的东西]]——问题只会在这些对象之间存在丰富的相互引用网络时出现)。


1
有没有办法获取动态创建类的定义,以便将其保存到文件中,然后像普通类一样使用? - tponthieux

3

你正在对类对象本身进行pickle,而不是类的实例对象。如果重新创建类对象,则此方法将无法正常工作。但是,只要类对象存在,对类的实例对象进行pickle就可以正常工作。


我想我明白你的意思,但是经过检查,type(result) 是 <type 'instance'>,result.class 是 <class suds.sudsobject.AdvertiserSearchResponse at 0x03373060>,所以我不是在尝试对实例进行pickle吗? - Mat
从粘贴的代码来看,似乎您正在pickle一个实例,但是您提到的错误表明您正在pickle一个类。 - Håvard S
好的,那我就不会完全疯掉了 :) 如果我删除最新协议的-1,我会得到不同的错误,我将修改问题以包括它,看看是否能提供更多信息。 - Mat

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接