我想持久地抓住来自reverend.thomas.Bayes
的对象。当然,如果我试图直接挑选其中一个类,我会得到:
TypeError: can't pickle instancemethod objects
要解决这个问题,我尝试过声明两个函数:
import types
from itertools import chain
from copy import copy
from reverend.thomas import Bayes
def prepare_bayes_for_pickle(bayes_obj):
dic = copy(bayes_obj.__dict__) #I also tried using deepcopy instead of copy
for k in dic:
if type(k) == types.MethodType:
dic.pop(k)
return dic
def reconstruct_bayes_from_pickle(bayes_dic):
b = Bayes()
# Merge b with bayes_dic, with bayes_dic taking precedence
dic = dict(chain(bayes_dic, b))
b.__dict__ = dic
return b
基本上,我尝试复制对象的__dict__
,并尝试通过针对instancemethod
测试类型来移除types.MethodType
。
然后我会通过创建一个新的Bayes
对象重新构建该对象,然后将其与bayes_dic
合并(在UnPickled之后)。
但是,我还没有达到第二种方法,因为我仍然无法在没有得到原始错误的情况下挑选从prepare_bayes_for_pickle
返回的对象。
答案 0 :(得分:2)
更好的解决方案是在__getstate__
课程中添加Bayes
方法(附带__setstate__
):
import types
from reverend.thomas import Bayes
def Bayes__getstate__(self):
state = {}
for attr, value in self.__dict__.iteritems():
if not isinstance(value, types.MethodType):
state[attr] = value
elif attr == 'combiner' and value.__name__ == 'robinson':
# by default, self.combiner is set to self.robinson
state['combiner'] = None
return state
def Bayes__setstate__(self, state):
self.__dict__.update(state)
# support the default combiner (an instance method):
if 'combiner' in state and state['combiner'] is None:
self.combiner = self.robinson
Bayes.__getstate__ = Bayes__getstate__
Bayes.__setstate__ = Bayes__setstate__
现在Bayes
类可以随时进行pickle和unpickled而无需额外处理。
我确实看到该类有一个self.cache = {}
映射;也许在酸洗时应该排除它?如果是这种情况,请在__getstate__
中忽略它并在self.buildCache()
中致电__setstate__
。
答案 1 :(得分:0)
k
是一个键,即属性/方法名称。您需要测试属性本身:
if type(dic[k]) == types.MethodType:
^~~~~~ here
我更喜欢使用理解;您还应该使用isinstance
:
dic = dict((k, v) for k, v in bayes_obj.__dict__
if not isinstance(v, types.MethodType))
答案 2 :(得分:0)
这听起来像是一个方形钉,适合圆孔。如何使用pickle来挑选参数,并使用unpickle重建reverand.Thomas.Bayes
对象?
>>> from collections import namedtuple
>>> ArgList = namedtuple('your', 'arguments', 'for', 'the', 'reverand')
>>> def pickle_rtb(n):
... return pickle.dumps(ArgList(*n.args))
...
>>> def unpickle_rtb(s):
... return reverand.Thomas.Bayes(*pickle.loads(s))
...
>>> s = pickle_rtb(reverand.Thomas.Bayes(1, 2, 3, 4, 5)) # note arguments are a guess
>>> rtb = unpickle_norm(s)
灵感来自this SO问题。