Możesz serializować kod bajtowy funkcji, a następnie zrekonstruować go w obiekcie wywołującym. Marszałek moduł może być stosowane do przedmiotów uszeregować kodów, które mogą być ponownie zmontowane w funkcji. to znaczy:
import marshal
def foo(x): return x*x
code_string = marshal.dumps(foo.func_code)
Następnie w procesie zdalnym (po przesłaniu code_string):
import marshal, types
code = marshal.loads(code_string)
func = types.FunctionType(code, globals(), "some_func_name")
func(10) # gives 100
Kilka zastrzeżeń:
Format marszałka (w tym przypadku dowolny kod bajtowy Pythona) może nie być kompatybilny między głównymi wersjami Pythona.
Działa tylko w przypadku implementacji cpython.
Jeśli funkcja odwołuje się do elementów globalnych (w tym zaimportowanych modułów, innych funkcji itp.), Które musisz odebrać, musisz je również serializować lub odtworzyć po stronie zdalnej. Mój przykład podaje tylko globalną przestrzeń nazw zdalnego procesu.
Prawdopodobnie będziesz musiał zrobić trochę więcej, aby obsługiwać bardziej złożone przypadki, takie jak zamknięcia lub funkcje generatora.
marshal
moduł do serializacji słownika słowników zainicjowanych jakodefaultdict(lambda : defaultdict(int))
. Ale zwraca błądValueError: unmarshallable object
. Uwaga: używam pythona 2.7. Dowolny pomysł? Dziękifoo.func_code
podnosiAttributeError
. Czy jest inny sposób uzyskania kodu funkcji?Sprawdź Dill , który rozszerza bibliotekę pickle Pythona o obsługę większej liczby typów, w tym funkcji:
Obsługuje również odniesienia do obiektów w zamknięciu funkcji:
źródło
Pyro jest w stanie zrobić to za Ciebie .
źródło
Najprostszym sposobem jest prawdopodobnie
inspect.getsource(object)
(zobacz moduł inspect ), który zwraca String z kodem źródłowym funkcji lub metody.źródło
Wszystko zależy od tego, czy generujesz funkcję w czasie wykonywania, czy nie:
Jeśli to zrobisz -
inspect.getsource(object)
nie będzie działać dla funkcji generowanych dynamicznie, ponieważ pobiera źródło obiektu z.py
pliku, więc jako źródło można pobrać tylko funkcje zdefiniowane przed wykonaniem.A jeśli twoje funkcje i tak są umieszczone w plikach, dlaczego nie dać odbiorcom dostępu do nich i przekazywać tylko nazwy modułów i funkcji.
Jedynym rozwiązaniem dla dynamicznie tworzonych funkcji, które przychodzi mi do głowy, jest skonstruowanie funkcji jako łańcucha przed transmisją, nadaniem źródła, a następnie
eval()
po stronie odbiornika.Edycja:
marshal
rozwiązanie wygląda również całkiem sprytnie, nie wiedziałem, że możesz serializować coś innego niż wbudowaneźródło
cloud
Pakiet (PIP zainstalować chmurę) może marynowane dowolnego kodu, w tym zależności. Zobacz https://stackoverflow.com/a/16891169/1264797 .źródło
Teraz
źródło
Możesz to zrobić:
Teraz
transmit(fn_generator())
wyśle rzeczywistą definicjęfn(x,y)
zamiast odniesienia do nazwy modułu.Możesz użyć tej samej sztuczki do wysyłania klas przez sieć.
źródło
Podstawowe funkcje używane w tym module obejmują zapytanie, a ponadto zapewniają najlepszą kompresję w sieci; zobacz pouczający kod źródłowy:
y_serial.py module :: hurtownia obiektów Pythona z SQLite
„Serializacja + trwałość: w kilku linijkach kodu skompresuj i dodaj adnotacje do obiektów Pythona do SQLite, a następnie odzyskaj je chronologicznie za pomocą słów kluczowych bez żadnego SQL. Najbardziej przydatny„ standardowy ”moduł bazy danych do przechowywania danych bez schematu.”
http://yserial.sourceforge.net
źródło
Cloudpickle jest prawdopodobnie tym, czego szukasz. Cloudpickle jest opisana w następujący sposób:
Przykład użycia:
źródło
Oto klasa pomocnicza, której możesz użyć do zawijania funkcji, aby były one pikowalne. Zastrzeżenia, o których już wspomniano,
marshal
będą miały zastosowanie, ale staramy się używać marynaty, gdy tylko jest to możliwe. Nie podejmuje się żadnych wysiłków, aby zachować wartości globalne lub zamknięcia podczas serializacji.źródło