为什么我不能腌制这个物体?

Ben*_*hes 14 python

我有一个班级(下):

class InstrumentChange(object):
    '''This class acts as the DTO object to send instrument change information from the
       client to the server. See InstrumentChangeTransport below
    '''
    def __init__(self, **kwargs):
        self.kwargs = kwargs
        self._changed = None

    def _method_name(self, text):
        return text.replace(' ','_').lower()

    def _what_changed(self):
        ''' Denotes the column that changed on the instrument returning the column_name of what changed.'''
        if not self._changed:
            self._changed = self._method_name(self.kwargs.pop('What Changed'))

        return self._changed

    def __getattr__(self, attr):
        for key in self.kwargs.iterkeys():
            if self._method_name(key) == attr:
                return self.kwargs[key]

    def __str__(self):
        return "Instrument:%s" % self.kwargs

    __repr__ = __str__

    what_changed = property(_what_changed)
Run Code Online (Sandbox Code Playgroud)

当我运行以下测试时:

def test_that_instrumentchangetransport_is_picklable(self):
        test_dict = {'Updated': 'PAllum', 'Description': 'BR/EUR/BRAZIL/11%/26/06/2017/BD',
        'Ask Q': 500, 'Bbg': 'On', 'C Bid': 72.0, 'Benchmark': 'NL/USD/KKB/7.000%/03/11/2009/BD',
        'ISIN': 'XS0077157575', 'Bid YTM': 0.0, 'Bid Q': 100, 'C Ask': 72.25, 'Ask YTM': 0.0, 'Bid ASW': 0.0,
        'Position': 1280000, 'What Changed': 'C Bid', 'Ask ASW': 0.0}
        ins_change = InstrumentChangeTransport(**test_dict)
        assert isinstance(ins_change, InstrumentChangeTransport)

        # Create a mock filesystem object
        file = open('testpickle.dat', 'w')
        file = Mock()
        pickle.dump(ins_change, file)
Run Code Online (Sandbox Code Playgroud)

我明白了:

Traceback (most recent call last):
  File "c:\python23\lib\site-packages\nose-0.11.0-py2.3.egg\nose\case.py", line 183, in runTest
    self.test(*self.arg)
  File "C:\Code\branches\demo\tests\test_framework.py", line 142, in test_that_instrumentchangetransport_is_picklable
    pickle.dump(ins_change, file)
  File "C:\Python23\Lib\copy_reg.py", line 83, in _reduce_ex
    dict = getstate()
TypeError: 'NoneType' object is not callable
Run Code Online (Sandbox Code Playgroud)

我看过pickle文档,但我不太清楚.

有任何想法吗?

Ale*_*lli 33

你的代码有几个小的"侧面"问题:在测试中使用的类名中突然出现'Transport'(它不是你定义的类名),对内置标识符file作为本地的可疑践踏变量(不要这样做 - 它不会在这里受到伤害,但是践踏内置标识符的习惯有一天会引起神秘的错误),Mock已经注意到它的误用,默认使用最慢的,最简单的酸洗协议和文本而不是pickle文件的二进制文件.

然而,正如@coonj所说,其核心是缺乏国家控制.一个"普通"类不需要它(因为self.__dict__默认情况下,在缺少状态控制且没有其他特性的类中得到pickle和unpickled) - 但是因为你的覆盖__getattr__不适用于你的类.您只需要两个非常简单的方法:

def __getstate__(self): return self.__dict__
def __setstate__(self, d): self.__dict__.update(d)
Run Code Online (Sandbox Code Playgroud)

这基本上告诉pickle你像对待正常的一样对待你的类self.__dict__,尽管存在的是,表示整个实例状态__getattr__.

  • @coonj,我想人们很难理解为什么人们需要定义状态处理方法,因为通常它们不需要(并且没有明确的文件证明`__getattr__`使它们成为必要). (5认同)

Jas*_*oon 7

它失败了,因为找不到__getstate__()你的对象.Pickle需要这些来确定如何挑选/取消对象.你只需要__getstate__()__setstate__()方法.

请参阅文档中的TextReader示例:http://docs.python.org/library/pickle.html

更新:我刚看了Mock模块sourceforge页面,我认为你也错误地使用它了.你正在嘲笑一个文件对象,但是当pickle尝试从中读取时,它将不会getattr()返回任何内容,这就是为什么不返回任何内容.