2014-09-01 10 views
9

w odpowiedzi na Python pickle: dealing with updated class definitions, autor pakietu dill pisze.Jak używać kopru do serializacji definicji klasy?

„Ok, dodałem tę funkcję do koperku w najnowszej wersji na github realizowane przy znacznie mniejszym oszustwa niż myślałem ... po prostu serializuje definicję klasy z ogórkiem i voila. "

Po zainstalowaniu dill i majstrowaniu przy nim, nie jest dla mnie oczywiste, jak faktycznie korzystać z tej funkcji w dill. Czy ktoś może podać wyraźny przykład? Chciałbym wybrać instancję klasy, a także serializować definicję klasy.

(Jestem nowy dla Pythona i ja ta funkcjonalność wydaje się niezwykle ważna, ponieważ od kiedy wytrawi się obiekt, byłoby wspaniale, aby uzyskać jak najbliżej gwarancji, że można spojrzeć na obiekt (może być wynikiem symulacja) w przyszłości po zmianie definicji klasy i nie śledziłeś wszystkich zmian w łatwo dostępny sposób).

Odpowiedz

3

Gdyby ta funkcja była tak ważna, byłaby w rdzeniu językowym przez teraz. :-) Nie, to nie jest ważne, aby używać Pythona w dowolnej zaawansowanej formie - a jeśli masz projekt, który polega na możliwości ponownego tworzenia obiektów w starych modelach - co jest możliwe, musisz uważnie pomyśleć o tym i prawdopodobnie zachowa stare modele w jawnym kodzie, zamiast serializacji.

Moja rada to po prostu "zostaw to osobno", dopóki nie będziesz tego potrzebować, i porównasz ją z innymi rozwiązaniami, takimi jak silna polityka migracyjna modelu.

Powiedziałem, że próbowałem koperku i działa jak w reklamie: może serializować klasę tak, jak piksel może wykonywać zwykłe obiekty za pomocą wywołań "dump" i "dumps", i odbudować obiekt klasy z "load" i "loads".

To, co prawdopodobnie powoduje, że się mylisz, polega na tym, że serializacja obiektu (poprzez pikle lub koper) nie zawiera ani kodu źródłowego (tzn. Rzeczywistych wierszy tekstu kodu Pythona używanego do definiowania klasy), ani jego nazwy.

Tak więc, jeśli klasa ma nazwę "A", jeśli jest serializowana, jeśli potrzebujesz tej nazwy po "usunięciu" jej, musisz ponownie przypisać jej nazwę w globalnej przestrzeni nazw. Jego nazwa orignal jest zachowana w jego atrybucie __name__. (i dla twoich celów wielu wersji tego samego modelu, żyjących razem, doprowadziłoby to do wielu konfliktów).

Zatem:

class A(object): 
    ... 

import dill 

dill.dump(A, open("myfile", "w")) 

del A 
.... 
someclass = dill.load(open("myfile")) 
print (someclass.__name__) 
globals()[someclass.__name__] = someclass 
# at this point you have the "A" class back in the global namespace 
4

myślę szukasz jednej z następujących funkcjonalności ...

Tu zbudować klasy i instancji, a następnie zmienić definicję klasy. Marynowane klasa i instancja nadal są unpicklable ponieważ dill pikle kod źródłowy dla klasy domyślnie ... i zarządza posiadające kilka klas o tej samej nazwie w przestrzeni nazw (robi to po prostu poprzez zarządzanie wskaźnik odniesienia do definicji klas).

Python 2.7.8 (default, Jul 13 2014, 02:29:54) 
[GCC 4.2.1 Compatible Apple Clang 4.1 ((tags/Apple/clang-421.11.66))] on darwin 
Type "help", "copyright", "credits" or "license" for more information. 
>>> import dill 
>>> 
>>> class Foo(object): 
... def bar(self, x): 
...  return x+self.y  
... y = 1 
... 
>>> f = Foo() 
>>> _Foo = dill.dumps(Foo) 
>>> _f = dill.dumps(f) 
>>> 
>>> class Foo(object): 
... def bar(self, x): 
...  return x*self.z 
... z = -1 
... 
>>> f_ = dill.loads(_f) 
>>> f_.y 
1 
>>> f_.bar(1) 
2 
>>> Foo_ = dill.loads(_Foo) 
>>> g = Foo_() 
>>> g.bar(1) 
2 

Pickle wysadziłby się w powyższym.Jeśli nie chcesz, aby dill serializuje jawnie klasę i robić to, co robi pickle, możesz poprosić o jej przygotowanie w oparciu o .

Teraz, w poniższym przykładzie, pracujemy z nową definicją klasy i wyodrębniamy źródło z obiektu, a następnie zapisujemy do pliku. Dodatkowo możemy zrzucić źródło do pliku (tutaj używam pliku tymczasowego), aby można go było później zaimportować.

>>> sFoo = dill.source.getsource(Foo) 
>>> print sFoo 
class Foo(object): 
    def bar(self, x): 
    return x*self.z 
    z = -1 

>>> open('myFoo.py', 'w').write(sFoo)  
>>> 
>>> f = dill.temp.dump_source(Foo, dir='.') 
>>> f.name 
'/Users/mmckerns/dev/tmpM1dzYN.py' 
>>> from tmpM1dzYN import Foo as _Foo_ 
>>> h = _Foo_() 
>>> h.bar(2) 
-2 
>>> from myFoo import Foo as _SFoo_ 
>>> _SFoo_.z 
>>> -1 
>>> 

Mam nadzieję, że to pomaga.

+0

Jeśli chodzi o twój pierwszy blok kodu, uruchamiam go i wysadza się dokładnie tak, jak "pikle": AttributeError: Obiekt "Foo" nie ma atrybutu "y". circa line 25. Szkoda, ponieważ brzmiało jak instancja magii, a przechowywanie obiektów z koperkiem w bazie danych byłoby łatwiejsze do utrzymania. Jest więc ogromny przypadek użycia. Dill 0.2.7.1, domyślne ustawienia kopru (byref False). Mam nadzieję, że to błąd operatora, ale cięcie i wklejanie jest solidnie w moim zestawie umiejętności. – piccolbo

+0

Błąd jest specyficzny dla ipython. Wielkie westchnienie ulgi, ale wciąż zagadkowe ... zbada i otworzy bilet – piccolbo

+0

@piccolbo: Weird. Mogę powtórzyć zachowanie w 'ipython' - więc muszą być mucking z czymś nieoczekiwanym. Wydaje się, że to nowe zachowanie. Hmm. Widziałem twój bilet, dzięki. –

Powiązane problemy