141 Stimmen

Gibt es eine einfache Möglichkeit, eine Python-Funktion (oder anderweitig serialisieren seinen Code) zu beizen?

Ich versuche, eine Funktion über eine Netzwerkverbindung zu übertragen (mit asyncore). Gibt es eine einfache Möglichkeit, eine Python-Funktion (eine, die, in diesem Fall zumindest, keine Nebenwirkungen haben) für die Übertragung wie diese zu serialisieren?

Im Idealfall hätte ich gerne ein Paar Funktionen, die diesen ähnlich sind:

def transmit(func):
    obj = pickle.dumps(func)
    [send obj across the network]

def receive():
    [receive obj from the network]
    func = pickle.loads(s)
    func()

147voto

Brian Punkte 112487

Sie könnten den Bytecode der Funktion serialisieren und ihn dann beim Aufrufer rekonstruieren. Die Marschall Modul kann zur Serialisierung von Code-Objekten verwendet werden, die dann wieder zu einer Funktion zusammengesetzt werden können, d.h.:

import marshal
def foo(x): return x*x
code_string = marshal.dumps(foo.__code__)

Dann in dem entfernten Prozess (nach der Übertragung von code_string):

import marshal, types

code = marshal.loads(code_string)
func = types.FunctionType(code, globals(), "some_func_name")

func(10)  # gives 100

Ein paar Vorbehalte:

  • Das Format von Marshal (bzw. von jedem Python-Bytecode) ist möglicherweise nicht mit allen größeren Python-Versionen kompatibel.

  • Funktioniert nur bei cpython-Implementierung.

  • Wenn die Funktion auf Globals verweist (einschließlich importierter Module, anderer Funktionen usw.), die Sie abrufen müssen, müssen Sie diese ebenfalls serialisieren oder auf der entfernten Seite neu erstellen. In meinem Beispiel wird nur der globale Namensraum des entfernten Prozesses angegeben.

  • Um komplexere Fälle zu unterstützen, wie z. B. Closures oder Generatorfunktionen, müssen Sie wahrscheinlich etwas mehr tun.

61voto

Josh Rosen Punkte 12873

Überprüfen Sie Dill die die Pickle-Bibliothek von Python erweitert, um eine größere Anzahl von Typen, einschließlich Funktionen, zu unterstützen:

>>> import dill as pickle
>>> def f(x): return x + 1
...
>>> g = pickle.dumps(f)
>>> f(1)
2
>>> pickle.loads(g)(1)
2

Sie unterstützt auch Verweise auf Objekte in der Schließung der Funktion:

>>> def plusTwo(x): return f(f(x))
...
>>> pickle.loads(pickle.dumps(plusTwo))(1)
3

13voto

RichieHindle Punkte 256891

Pyro ist in der Lage dies für Sie tun .

13voto

Aaron Digulla Punkte 308693

Der einfachste Weg ist wahrscheinlich inspect.getsource(object) (siehe die Modul prüfen ), die einen String mit dem Quellcode einer Funktion oder einer Methode zurückgibt.

9voto

kurczak Punkte 1511

Es kommt darauf an, ob Sie die Funktion zur Laufzeit generieren oder nicht:

Wenn Sie das tun - inspect.getsource(object) funktioniert nicht für dynamisch generierte Funktionen, da es die Objektquelle von .py Datei, so dass nur Funktionen, die vor der Ausführung definiert wurden, als Quelle abgerufen werden können.

Und wenn Ihre Funktionen ohnehin in Dateien gespeichert sind, warum sollten Sie dem Empfänger nicht den Zugriff darauf ermöglichen und nur Modul- und Funktionsnamen weitergeben.

Die einzige Lösung für dynamisch erstellte Funktionen, die mir einfällt, ist, die Funktion vor der Übertragung als String zu konstruieren, die Quelle zu übertragen und dann eval() es auf der Empfängerseite.

Bearbeiten: die marshal Die Lösung sieht auch ziemlich clever aus, ich wusste nicht, dass man etwas anderes als Built-Ins serialisieren kann.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X