2009-08-28 15 views
6

(Możesz czytać this pytanie dla niektórych tle)Wdziękiem degradujący marynowanie w Pythonie

chciałbym mieć wdzięcznie degradujący sposób na marynowane obiektów w Pythonie.

Podczas wytrawiania obiektu, nazwijmy go głównym obiektem, czasami Pickler podnosi wyjątek, ponieważ nie może on zaliczyć określonego pod-obiektu głównego obiektu. Na przykład błąd, który często otrzymuję, to "nie można pobierać obiektów modułu". To dlatego, że odwołuję się do modułu z głównego obiektu.

Wiem, że mogę napisać coś, co zastąpi ten moduł elewacją, która zawierałaby atrybuty modułu, ale miałoby to swoje własne problemy (1).

A więc chciałbym użyć funkcji wytrawiania, która automatycznie zastąpi moduły (i wszelkie inne trudne do ukrycia obiekty) fasadami, które zawierają ich atrybuty. To może nie wytworzyć doskonałego wytrawiania, ale w wielu przypadkach wystarczy.

Czy jest coś takiego? Czy ktoś ma pomysł, jak do tego podejść?


(1) Jednym z problemów byłoby to, że moduł może odwoływać się do innych modułów z jego wnętrza.

+1

Java Beans .. Python Pickles .. Chciałbym zdusić frajerów, którzy wymyślają to Cudowne rzeczy –

Odpowiedz

0

Co powiecie na następujące, które jest opakowaniem, które można wykorzystać do owinięcia niektórych modułów (może dowolnego modułu) w coś, co jest w stanie wykorzystać. Następnie można podklasować obiekt Pickler, aby sprawdzić, czy obiekt docelowy jest modułem, a jeśli tak, zawiń go. Czy to osiąga to, czego pragniesz?

class PickleableModuleWrapper(object): 
    def __init__(self, module): 
     # make a copy of the module's namespace in this instance 
     self.__dict__ = dict(module.__dict__) 
     # remove anything that's going to give us trouble during pickling 
     self.remove_unpickleable_attributes() 

    def remove_unpickleable_attributes(self): 
     for name, value in self.__dict__.items(): 
      try: 
       pickle.dumps(value) 
      except Exception: 
       del self.__dict__[name] 

import pickle 
p = pickle.dumps(PickleableModuleWrapper(pickle)) 
wrapped_mod = pickle.loads(p) 
0

Hmmm, coś w tym stylu?

import sys 

attribList = dir(someobject) 
for attrib in attribList: 
    if(type(attrib) == type(sys)): #is a module 
     #put in a facade, either recursively list the module and do the same thing, or just put in something like str('modulename_module') 
    else: 
     #proceed with normal pickle 

Oczywiście, to pójdzie do rozszerzenia klasy ogórka z przeprogramowana metodą zrzutu ...

3

Możesz zdecydować i wdrożyć jak każdy rodzaj wcześniej unpicklable dostaje marynowane i unpickled: patrz biblioteki standardowej moduł copy_reg (przemianowany na copyreg w Pythonie 3. *).

Zasadniczo należy podać funkcję, która, biorąc pod uwagę instancję typu, redukuje ją do krotki - z tym samym protokołem, co metoda specjalna reduce (z tym wyjątkiem, że metoda specjalna zredukowana nie przyjmuje argumentów, ponieważ pod warunkiem, że jest wywołana bezpośrednio na obiekcie, a funkcja, którą podasz, przyjmie obiekt jako jedyny argument).

Zwykle krotka, którą zwrócisz, ma 2 pozycje: wywoływalną i krotkę argumentów do przekazania. Podpowiedź musi być zarejestrowana jako "bezpieczny konstruktor" lub mieć atrybut __safe_for_unpickling__ z wartością rzeczywistą. Te przedmioty będą marynowane, a przy odpalaniu czas wywołania będzie wywoływany z podanymi argumentami i musi zwrócić usunięty obiekt.

Załóżmy na przykład, że chcesz po prostu wybrać moduły po nazwie, aby je rozpakować, oznacza tylko ich ponowne zaimportowanie (np. Załóżmy, że nie zależy ci na dynamicznie modyfikowanych modułach, zagnieżdżonych pakietach itp. zwykłe moduły najwyższego poziomu).Następnie:

>>> import sys, pickle, copy_reg 
>>> def savemodule(module): 
... return __import__, (module.__name__,) 
... 
>>> copy_reg.pickle(type(sys), savemodule) 
>>> s = pickle.dumps(sys) 
>>> s 
"c__builtin__\n__import__\np0\n(S'sys'\np1\ntp2\nRp3\n." 
>>> z = pickle.loads(s) 
>>> z 
<module 'sys' (built-in)> 

Używam staroświecką formę ASCII zalewy, tak aby s, łańcuch zawierający marynatę, jest łatwa do zbadania: instruuje unpickling zadzwonić wbudowanej funkcji importu, przy czym ciąg sys jako jedyny argument. I z pokazuje, że to faktycznie daje nam z powrotem wbudowany moduł sys w wyniku rozprysków, zgodnie z potrzebami.

Teraz będziesz musiał sprawić, że rzeczy będą bardziej skomplikowane niż tylko __import__ (będziesz musiał radzić sobie z zapisywaniem i przywracaniem dynamicznych zmian, nawigacją w zagnieżdżonym obszarze nazw itp.), A więc będziesz musiał również zadzwoń pod numer copy_reg.constructor (przekazując jako argument swoją własną funkcję, która wykonuje tę pracę) przed copy_reg funkcją oszczędzania modułów, która zwraca twoją drugą funkcję (oraz, jeśli w oddzielnym uruchomieniu, również przed odfukcjonowaniem tych pikli, które zostały wykonane za pomocą tej funkcji). Ale mam nadzieję, że te proste przypadki pomogą pokazać, że nie ma w tym nic naprawdę "skomplikowanego"! -)

+0

@Alex Martelli: Kiedy używam copy_reg.pickle, jaki jest zakres, w którym ta zmiana będzie miała znaczenie? Chcę, aby ludzie mogli importować moją pracę bez zmiany jakichkolwiek wartości systemowych, które mogłyby zniszczyć ich program. –

+0

'copy_reg' jest globalne. Ale jeśli nie są to aktualnie moduły (co jest niemożliwe z powodu domyślnych ustawień systemowych), nie może "zniszczyć ich programu", aby moduły mogły być wybieralne. –

+0

@Alex Martelli: Ale jeśli wpadliby na ten sam problem i zdefiniowali moduł trawiący w inny sposób, mielibyśmy problem. Wierzę, że jestem uprzejmy i nie zmieniam stanu systemu. Wierzę, że po zaimportowaniu jakiegoś modułu do Pythona nie powinieneś się martwić, że zakłóci on działanie globalnych systemów, i że ważne jest posiadanie narzędzi, które pozwolą ci uniknąć tego rodzaju "nieuprzejmości" w twoich modułach. –