Python 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

编写几乎pickle对象的所有属性,但排除少数属性的
\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