Python Pickle除一个属性外的所有属性
编写几乎pickle对象的所有属性,但排除少数属性的Python Pickle除一个属性外的所有属性,python,pickle,Python,Pickle,编写几乎pickle对象的所有属性,但排除少数属性的\uuu getstate\uuu方法的最佳方法是什么 我有一个具有许多属性的对象,包括一个引用instancemethod的对象。instancemethod不可pickle,因此我在尝试pickle此对象时出错: class Foo(object): def __init__(self): self.a = 'spam' self.b = 'eggs' self.c = 42
\uuu getstate\uuu
方法的最佳方法是什么
我有一个具有许多属性的对象,包括一个引用instancemethod的对象。instancemethod不可pickle,因此我在尝试pickle此对象时出错:
class Foo(object):
def __init__(self):
self.a = 'spam'
self.b = 'eggs'
self.c = 42
self.fn = self.my_func
def my_func(self):
print 'My hovercraft is full of eels'
import pickle
pickle.dumps(Foo()) # throws a "can't pickle instancemethod objects" TypeError
这个\uuuu getstate\uuuu
方法修复了这个问题,但是我必须手动包含我想要序列化的所有属性:
def __getstate__(self):
return { 'a': self.a, 'b': self.b, 'c': self.c }
如果我有一个具有许多属性的对象,或者这个对象经常更改,那么这个对象就不具有很强的可伸缩性或可维护性
我能想到的唯一替代方法是某种帮助函数,它根据类型遍历对象的属性并将它们(或不添加)添加到字典中
我能想到的唯一替代方法是某种帮助函数,它根据类型遍历对象的属性并将它们(或不添加)添加到字典中
是的,如果你想要足够的“魔力”让自己变得懒惰(和/或允许动态添加属性),我认为这就是你剩下的。请记住,“pickle
无法处理此问题”并不是您不希望在pickle状态中包含某些内容的唯一原因
但这并不像你想象的那么难,假设你有“我应该泡菜吗?”逻辑的代码:
使用前面的答案:
def __getstate__(self):
return dict((k, v) for k, v in self.__dict__.iteritems()
if not is_instance_method(getattr(self, k)))
尽管是_instance_方法
操作也可以通过采用已知的实例方法(例如my_func
)并采用其类型来执行,而不那么“神奇”
def __getstate__(self):
instancemethod = type(self.my_func)
return dict((k, v) for k, v in self.__dict__.iteritems()
if not isinstance(getattr(self, k), instancemethod))
您始终可以删除坏项:
def __getstate__(self):
state = self.__dict__
del state[...]
return state
我会直截了当地解决您的问题,首先尝试序列化所谓的“不可酸洗”项。 要做到这一点,我将使用,它可以序列化python中的几乎任何内容。Dill还可以帮助您理解代码失败时是什么导致酸洗失败
>>> import dill
>>> dill.loads(dill.dumps(your_bad_object))
>>> ...
>>> # if you get a pickling error, use dill's tools to figure out a workaround
>>> dill.detect.badobjects(your_bad_object, depth=0)
>>> dill.detect.badobjects(your_bad_object, depth=1)
>>> ...
如果您确实想这样做,您可以使用dill的
badobjects
(或其他检测函数之一)递归地潜入对象的引用链,并弹出不可点击的对象,而不是像上面那样在每个深度调用它。\uuuuuuuuuuuuuuuuu
解决方案
如果使用的是插槽,则可以避免重复要排除的成员:
class C(object):
_pickle_slots = ['i']
__slots__ = _pickle_slots + ['j']
def __init__(self, i, j):
self.i = i
self.j = j
def __getstate__(self):
return (None, {k:getattr(self, k) for k in C._pickle_slots })
o = pickle.loads(pickle.dumps(C(1, 2), -1))
# i is there
assert o.i == 1
# j was excluded
try:
o.j
except:
pass
else:
raise
在Python 2.7.6中测试。对于您的特定情况(防止函数被pickle),请使用以下命令:
self.\uuuuu class\uuuuuu.fn=self.\uuuuu class\uuuuu.my\u func
现在,不是将函数添加到类的实例中,而是将其添加到类本身中,因此函数不会被pickle。如果您希望每个实例都有自己版本的fn
,那么这将不起作用
我的场景是,我想有选择地将
get_absolute\u url
添加到一些Django模型中,我想在抽象的BaseModel
类中定义它。我有一个self.get\u absolute\u url=…
,遇到了pickle
问题。刚刚在作业中添加了\uuuuu class\uuuuu
,解决了我的问题。+1供气垫船参考(除此之外,这是一个有价值的问题),但这会修改原始对象,这是我不想要的。我想我可以做一个self.\uu dict\uuu的深度拷贝,并从拷贝中删除属性。不过,这可能会带来其他问题。@Mike:oops,忘了复制dict。是的,目的是先复制它。@Mike:请注意,您只需要一个浅拷贝,因为您从不修改键和值(只修改dict本身)。为编辑。copy()
。然后,我认为这是对原始问题的一个优雅的回答,它集中在一个或几个已知名称的属性上。那些带有列表/听写理解和昂贵类型检查的答案是不必要的。那么父类呢?getstate函数对父属性的处理是否正确?这里的A稍微整洁一些:{k:v代表k,v在self.\uu dict\uuuu.iteritems()如果pickle(v)}
和@Venza:我认为它可以很好地处理继承。(它不会包含任何类属性。)更新以使代码现代化,因为OP没有标记为2.x。
class C(object):
_pickle_slots = ['i']
__slots__ = _pickle_slots + ['j']
def __init__(self, i, j):
self.i = i
self.j = j
def __getstate__(self):
return (None, {k:getattr(self, k) for k in C._pickle_slots })
o = pickle.loads(pickle.dumps(C(1, 2), -1))
# i is there
assert o.i == 1
# j was excluded
try:
o.j
except:
pass
else:
raise