除了一个外序列化所有属性

30 投票
6 回答
8113 浏览
提问于 2025-04-16 21:10

怎么写一个 __getstate__ 方法,能把一个对象的几乎所有属性都保存起来,但又能排除掉一些呢?

我有一个对象,它有很多属性,其中有一个是指向实例方法的。实例方法是不能被保存的,所以当我尝试保存这个对象时就会出错:

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

这个 __getstate__ 方法解决了这个问题,但我得手动列出所有我想保存的属性:

def __getstate__(self):
    return { 'a': self.a, 'b': self.b, 'c': self.c }

如果我的对象有很多属性,或者这些属性经常变化,这样做就不太方便,也不容易维护。

我能想到的唯一替代办法就是写一个辅助函数,遍历对象的属性,根据属性的类型决定是否把它们添加到字典里。

6 个回答

4

你可以直接把那些不好的东西删掉:

def __getstate__(self):
    state = self.__dict__
    del state[...]
    return state
6

使用之前回答中的 is_instance_method 方法:

def __getstate__(self):
    return dict((k, v) for k, v in self.__dict__.iteritems()
                       if not is_instance_method(getattr(self, k)))

虽然我们也可以通过一种不那么“神奇”的方式来执行 is_instance_method 操作,比如拿一个已知的实例方法,比如 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))
14

我能想到的唯一替代方案就是写一个辅助函数,这个函数会遍历一个对象的属性,然后根据属性的类型决定是否把它们加到字典里。

是的,我觉得如果你想要一些“魔法”来让自己变得懒惰(或者允许动态添加属性),那这基本上就是你能做的了。要记住,“pickle 处理不了这个”并不是你可能不想把某些东西放进序列化状态的唯一原因。

不过,这并没有你想象的那么难,前提是你已经有了判断“我应该序列化这个吗?”的逻辑代码:

def __getstate__(self):
  return {k:v for (k, v) in self.__dict__.items() if should_pickle(v)}

撰写回答