Maison  >  Article  >  développement back-end  >  Introduction à la méthode de définition dynamique de fonctions en Python

Introduction à la méthode de définition dynamique de fonctions en Python

不言
不言avant
2019-03-19 09:19:092694parcourir

Cet article vous apporte une introduction à la méthode de définition dynamique des fonctions en Python. Il a une certaine valeur de référence. Les amis dans le besoin peuvent s'y référer.

Sous licence MIT

En Python, il n'existe pas de sucre syntaxique qui simplifie la définition des fonctions au moment de l'exécution. Toutefois, cela ne signifie pas que cela soit impossible ou difficile à réaliser.

from types import FunctionType

foo_code = compile('def foo(): return "bar"', "<string>", "exec")
foo_func = FunctionType(foo_code.co_consts[0], globals(), "foo")

print(foo_func())

Sortie :

bar

Analyse

En regardant le code ligne par ligne, vous verrez à quel point la barrière langue/interprète est fragile.

>>> from types import FunctionType

La documentation Python ne répertorie généralement pas les fonctionnalités qui ne sont pas destinées aux classes créées manuellement (ce qui est parfaitement raisonnable). Il existe trois façons de résoudre ce problème : help(), inspect (impossible d'inspecter les méthodes intégrées) et la solution finale, qui consiste à inspecter le code source de CPython. (Recommandé : Tutoriel Python)

Dans ce cas, help() et inspect peuvent faire le travail, mais l'examen du code source réel en révélera plus sur les détails des types de données.

>>> from inspect import signature
>>> signature(FunctionType)
<Signature (code, globals, name=None, argdefs=None, closure=None)>

1. code

est en interne un objet PyCode, qui est ouvert sur le monde extérieur en tant que types.CodeType. Les méthodes non intégrées ont un attribut __code__, qui stocke l'objet code correspondant. Les objets Types.CodeType peuvent être créés au moment de l’exécution à l’aide de la méthode compile() intégrée.

2. globales

Si une fonction fait référence à une variable qui n'est pas définie localement, mais qui est transmise en tant que paramètre, fournie par une valeur de paramètre par défaut ou fournie via un contexte de fermeture, elle recherchera dans le dictionnaire global.

La méthode intégrée globals() renvoie une référence à la table des symboles globaux du module actuel et peut donc être utilisée pour fournir un dictionnaire toujours cohérent avec l'état de la table actuelle. Il est également possible de passer dans n'importe quel autre dictionnaire (FunctionType((lambda: bar).__code__, {"bar" : "baz"}, "foo")() == "baz").

3. name (facultatif)

Contrôlez l'attribut __name__ de la fonction renvoyée. Seulement vraiment utile pour les lambdas (qui n'ont généralement pas de nom en raison de l'anonymat) et pour renommer les fonctions.

4. argdefs (facultatif)

Fournit un moyen de fournir des valeurs d'argument par défaut en passant un tuple contenant des objets de n'importe quel type (def foo(bar="baz" )). (FunctionType((lambda bar: bar).__code__, {}, "foo", (10,))() == 10).

5. fermeture (facultatif)

(ne devrait probablement pas être touchée si elle doit être exécutée dans d'autres machines virtuelles Python que CPython (PyPy, Jython,...) car cela dépend sérieusement de détails de mise en œuvre).

Un tuple d'objets cellules. Créer un objet cellule n'est pas tout à fait simple, car cela nécessite des appels aux composants internes de CPython, mais il existe une bibliothèque qui facilite la tâche : exalt (publicité sans vergogne). (Annotation : cette bibliothèque a été développée par l'auteur.)

>>> foo_code = compile('def foo(): return "bar"', "<string>", "exec")

compile() est une méthode intégrée, elle est donc également bien documentée.

le mode exécutable est utilisé car la définition d'une fonction nécessite plusieurs instructions.

>>> foo_func = FunctionType(foo_code.co_consts[0], globals(), "foo")

Agrége tout le contenu et attribue une fonction créée dynamiquement à une variable.

La fonction compilée par la phrase de code précédente devient la première constante de l'objet de code généré, donc pointer simplement vers foo_code n'est pas suffisant. C'est une conséquence directe du mode exécution, puisque l'objet code généré peut contenir plusieurs constantes.

>>> print(foo_func())

Les fonctions générées dynamiquement peuvent être appelées comme les autres fonctions.

Enfin

À l'exception des expériences, il existe très peu de scénarios dans lesquels des fonctions créées dynamiquement sont nécessaires.
Jouer avec les composants internes de Python est un excellent moyen d’en apprendre davantage sur le langage.
Traversez sans effort les frontières entre interprètes et langues si vous le souhaitez.


Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Cet article est reproduit dans:. en cas de violation, veuillez contacter admin@php.cn Supprimer