2011-01-13 8 views
29

Próbuję marynowane namedtuple:Python: Czy nie zalewa typu X, atrybut wyszukiwania udało

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() 

To daje następujący wynik:

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 

Co robię źle? Czy problem polegający na tym, że Bar jest członkiem Foo? (Moving definicję Bar na najwyższym poziomie rozwiązuje problemu, chociaż wciąż jestem ciekaw, dlaczego tak się dzieje.)

+4

Korzystanie python3 i marynowane Protokół 4 poprawki to –

Odpowiedz

26

Tak, fakt, że jest członkiem klasy jest problem:

>>> 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'> 

Problem polega na tym, że gdy namedtuple() zwraca obiekt typu, nie jest świadomy faktu, że jest on przypisany do elementu klasy - iw ten sposób informuje obiekt typu, że jego nazwa powinna być równa __main__.Bar, mimo że naprawdę powinna być __main__.Foo.Bar .

+2

Więc ... czy jest jakieś obejście, czy to jest po prostu zabronione? –

+0

'namedtuple' po prostu nie gra ładnie z klasami. Możesz napisać niestandardowy '__getstate__' dla obiektu, który zajmie się nim ręcznie. – Amber

+3

http://docs.python.org/library/pickle.html#object.__getstate__ – Amber

11

Klasy zagnieżdżania powodują, że zalewanie się nie udaje, ponieważ polega na ścieżce obiektu wewnątrz aplikacji, aby później ją zrekonstruować.

Natychmiastowym rozwiązaniem jest nie zagnieżdżanie klas, tj. Przenoszenie definicji Bar na zewnątrz obiektu Foo. Kod będzie działać tak samo.

Ale lepiej zrobić, aby nie używaćpickle w ogóle do przechowywania danych. Użyj innego formatu serializacji, na przykład json lub bazy danych, na przykład sqlite3.

Udało Ci się trafić w jedną z wielu niedogodności piklowania, jeśli zmienisz kod, zmienisz elementy lub dokonasz drobnych zmian strukturalnych, twoje dane staną się nie do pobrania.

Poza tym, ogórek ma inne wady: Jest powolny, niezabezpieczone, python-tylko ...

3

Korzystanie koperek zamiast zalewie tutaj pozwoli to zadziałało

Powiązane problemy