Python: невозможно сортировать тип X, сбой поиска атрибута
Я пытаюсь разжечь namedtuple
:
from collections import namedtuple
import cPickle
class Foo:
Bar = namedtuple('Bar', ['x', 'y'])
def baz(self):
s = set()
s.add(Foo.Bar(x=2, y=3))
print cPickle.dumps(s)
if __name__ == '__main__':
f = Foo()
f.baz()
Это приводит к следующему выводу:
Traceback (most recent call last):
File "scratch.py", line 15, in <module>
f.baz()
File "scratch.py", line 11, in baz
print cPickle.dumps(s)
cPickle.PicklingError: Can't pickle <class '__main__.Bar'>: attribute lookup __main__.Bar failed
Что я делаю неправильно? Проблема в том, что Bar
является членом Foo
? (Перемещение определения Bar
на верхний уровень решает проблему, хотя мне все еще интересно, почему это происходит.)
Ответы
Ответ 1
Да, тот факт, что это член класса является проблемой:
>>> class Foo():
... Bar = namedtuple('Bar', ['x','y'])
... def baz(self):
... b = Foo.Bar(x=2, y=3)
... print(type(b))
...
>>> a = Foo()
>>> a.baz()
<class '__main__.Bar'>
Проблема заключается в том, что когда namedtuple()
возвращает объект типа, он не знает о том, что ему присваивается член класса, и, следовательно, он сообщает, что тип объекта, который он набирает, должен быть __main__.Bar
, хотя это действительно должно быть __main__.Foo.Bar
.
Ответ 2
Вложенные классы приводят к откату pickle, так как он опирается на путь объекта внутри вашего приложения, чтобы впоследствии его восстановить.
Непосредственным решением является не встраивание классов, т.е. перемещение Bar
на внешний Foo
. Код будет работать все равно.
Но лучше всего не использовать pickle
вообще для хранения данных. Используйте другой формат сериализации, например json
, или базу данных, например sqlite3
.
Вы только что поразили одно из многих неудобств рассола, если вы меняете свой код, перемещаете вещи или иногда делаете небольшие структурные изменения, ваши данные становятся неактивными.
Кроме того, у рассола есть и другие недостатки: он медленный, небезопасный, только python...
Ответ 3
Использование укропа вместо рассола здесь позволит это работать