Vous pouvez sérialiser le bytecode de la fonction, puis le reconstruire sur l'appelant. Le module marshal peut être utilisé pour sérialiser des objets de code, qui peuvent ensuite être réassemblés en une fonction. c'est à dire:
import marshal
def foo(x): return x*x
code_string = marshal.dumps(foo.func_code)
Puis dans le processus distant (après avoir transféré code_string):
import marshal, types
code = marshal.loads(code_string)
func = types.FunctionType(code, globals(), "some_func_name")
func(10) # gives 100
Quelques mises en garde:
Le format de marshal (n'importe quel bytecode python d'ailleurs) peut ne pas être compatible entre les principales versions de python.
Ne fonctionnera que pour l'implémentation cpython.
Si la fonction fait référence à des globaux (y compris des modules importés, d'autres fonctions, etc.) que vous devez récupérer, vous devrez également les sérialiser ou les recréer du côté distant. Mon exemple lui donne simplement l'espace de noms global du processus distant.
Vous devrez probablement faire un peu plus pour prendre en charge des cas plus complexes, tels que les fermetures ou les fonctions de générateur.
marshal
module pour sérialiser un dictionnaire de dictionnaires initialisé en tant quedefaultdict(lambda : defaultdict(int))
. Mais cela renvoie l'erreurValueError: unmarshallable object
. Notez que j'utilise python2.7. Une idée? Mercifoo.func_code
augmenteAttributeError
. Existe-t-il un autre moyen d'obtenir le code de fonction?Découvrez Dill , qui étend la bibliothèque pickle de Python pour prendre en charge une plus grande variété de types, y compris des fonctions:
Il prend également en charge les références aux objets dans la fermeture de la fonction:
la source
Pyro est capable de le faire pour vous .
la source
Le moyen le plus simple est probablement
inspect.getsource(object)
(voir le module inspect ) qui retourne une chaîne avec le code source d'une fonction ou d'une méthode.la source
Tout dépend si vous générez la fonction au moment de l'exécution ou non:
Si vous le faites -
inspect.getsource(object)
ne fonctionnera pas pour les fonctions générées dynamiquement car il obtient la source de l'objet à partir du.py
fichier, donc seules les fonctions définies avant l'exécution peuvent être récupérées comme source.Et si vos fonctions sont de toute façon placées dans des fichiers, pourquoi ne pas leur donner accès au récepteur et ne transmettre que les noms de modules et de fonctions.
La seule solution pour les fonctions créées dynamiquement à laquelle je peux penser est de construire la fonction sous forme de chaîne avant la transmission, de transmettre la source, puis
eval()
du côté du récepteur.Edit: la
marshal
solution semble également assez intelligente, je ne savais pas que vous pouviez sérialiser quelque chose d'autre que des éléments intégrésla source
Le
cloud
package (pip install cloud) peut pickle du code arbitraire, y compris les dépendances. Voir https://stackoverflow.com/a/16891169/1264797 .la source
Maintenant
la source
Tu peux le faire:
Maintenant,
transmit(fn_generator())
enverra la définition réelle defn(x,y)
au lieu d'une référence au nom du module.Vous pouvez utiliser la même astuce pour envoyer des classes sur le réseau.
la source
Les fonctions de base utilisées pour ce module couvrent votre requête, et vous obtenez la meilleure compression sur le fil; voir le code source instructif:
module y_serial.py :: entreposer des objets Python avec SQLite
"Sérialisation + persistance :: en quelques lignes de code, compressez et annotez les objets Python dans SQLite; puis récupérez-les plus tard par mots-clés sans SQL. Module" standard "le plus utile pour une base de données pour stocker des données sans schéma."
http://yserial.sourceforge.net
la source
Cloudpickle est probablement ce que vous recherchez. Cloudpickle est décrit comme suit:
Exemple d'utilisation:
la source
Voici une classe d'aide que vous pouvez utiliser pour envelopper des fonctions afin de les rendre picklable. Les mises en garde déjà mentionnées
marshal
s'appliquent, mais un effort est fait pour utiliser le cornichon chaque fois que possible. Aucun effort n'est fait pour préserver les globaux ou les fermetures lors de la sérialisation.la source