Почему я не могу солить этот объект?

У меня есть класс (ниже):

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)

Когда я запускаю следующий тест:

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)

Я получаю:

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

Я посмотрел на документы рассола, но я не совсем понял.

Любые идеи?

Бен

Ответы

Ответ 1

В вашем коде есть несколько второстепенных "побочных" проблем: внезапное появление "транспорта" в имени класса, используемого в тесте (это не имя класса, которое вы определяете), сомнительное попирание встроенного идентификатора file как локальная переменная (не делайте этого - здесь это не повредит, но привычка попирать встроенные идентификаторы однажды вызовет загадочные ошибки), злоупотребления Mock, которые уже были отметил, что по умолчанию используется самый медленный, самый громоздкий протокол травления и текст, а не двоичный для файла pickle.

Однако, по сути, как говорит @coonj, это отсутствие государственного контроля. "Нормальный" класс ему не нужен (потому что self.__dict__ получает маринованные и незаселенные по умолчанию в классах, не имеющих контроля состояния и без других особенностей), но поскольку вы переопределяете __getattr__, который не применяется к вашему классу, Вам просто нужны еще два очень простых метода:

def __getstate__(self): return self.__dict__
def __setstate__(self, d): self.__dict__.update(d)

которые в основном говорят pickle относиться к вашему классу так же, как к обычным, принимая self.__dict__ как представляющее все состояние экземпляра, несмотря на существование __getattr__.

Ответ 2

Он не работает, потому что он не может найти __getstate__() для вашего объекта. Рассол нуждается в них, чтобы определить, как рассолковать/расклеить объект. Вам просто нужны методы __getstate__() и __setstate__().

См. пример TextReader в документах: http://docs.python.org/library/pickle.html

Обновление. Я просто просмотрел страницу sourceforge для модуля Mock, и я думаю, что вы также используете это неправильно. Вы издеваетесь над файловым объектом, но когда pickle пытается его прочитать, он ничего не получит, поэтому getattr() не возвращает ничего.

Ответ 3

    file = open('testpickle.dat', 'w')
    file = Mock()

Вы теряете здесь ссылку на открытый файл. Возможно, это проблема?