HOWTO · Python
Appeler une fonction à partir d'un nom de chaîne en Python
Il démontre comment appeler une fonction à partir d'une chaîne en Python
Sur cette page
Lorsqu’un nom de fonction est fourni sous forme de chaîne, recherchez-le dans un ensemble défini de fonctions autorisées, puis appelez l’objet fonction obtenu. Pour des commandes ou d’autres actions choisies par l’utilisateur, un dictionnaire est généralement la solution la plus claire : les noms disponibles sont visibles et une entrée arbitraire ne peut pas sélectionner du code sans rapport.
Utiliser un dictionnaire pour associer les noms autorisés aux fonctions
Définissez les fonctions normalement, puis associez les chaînes acceptées aux objets fonction correspondants. Recherchez le nom demandé et vérifiez que le résultat est appelable avant de l’invoquer. Cet exemple traite un nom inconnu sans tenter d’appel :
L’exécution fournie a terminé cet exemple autonome avec le code de sortie 0 et a affiché 8. Pour l’exécuter :
Le code et les libellés ou sorties affichés dans cette section restent en anglais.
def add(left, right):
return left + right
def multiply(left, right):
return left * right
functions = {"add": add, "multiply": multiply}
name = "add"
function = functions.get(name)
if callable(function):
print(function(5, 3))
else:
print(f"Unknown function: {name}")
8
Le dictionnaire constitue une liste d’autorisation : seules les fonctions dont le nom figure dans functions peuvent être sélectionnées. Utilisez .get() lorsqu’un nom absent est une entrée attendue, et déterminez comment l’application doit signaler ou traiter un nom inconnu. Si les fonctions prennent des arguments différents, validez également les arguments de l’opération sélectionnée ; retrouver un nom ne garantit pas que les arguments correspondent à la signature de l’appel.
Utiliser getattr() pour récupérer un attribut d’un objet ou d’un module
Utilisez getattr(object, name, default) lorsque la chaîne doit sélectionner un attribut précis d’un objet ou d’un module. Le troisième argument fournit une valeur de remplacement si cet attribut n’existe pas. Vérifiez ensuite que la valeur est appelable : un attribut existant peut être une donnée plutôt qu’une fonction.
L’exécution fournie a terminé cet exemple avec le code de sortie 0 et a affiché 8. Il récupère une méthode d’instance liée : Python associe calculator à la méthode, il suffit donc de transmettre les arguments restants de celle-ci. Pour l’exécuter :
Le code et les libellés ou sorties affichés dans cette section restent en anglais.
class Calculator:
def add(self, left, right):
return left + right
calculator = Calculator()
name = "add"
operation = getattr(calculator, name, None)
if callable(operation):
print(operation(5, 3))
else:
print(f"No callable attribute named {name}")
8
La même approche fonctionne avec un objet module, par exemple getattr(math, name, None) après avoir importé math. La recherche d’une méthode d’instance sur l’instance renvoie une méthode liée ; sur la classe, elle renvoie la fonction non liée, à laquelle il faut transmettre l’instance comme argument. Si la chaîne vient de l’extérieur de votre code, limitez l’objet source et les noms d’attribut autorisés.
Utiliser globals() et locals() uniquement lorsque l’espace de noms est choisi délibérément
globals() renvoie l’espace de noms global du module courant. Il ne renvoie pas les variables locales. Une recherche dans l’espace global peut être utile lorsque les fonctions se trouvent délibérément dans ce module. L’exécution fournie a terminé cet exemple avec le code de sortie 0 et a affiché 8. Pour l’exécuter :
Le code et les libellés ou sorties affichés dans cette section restent en anglais.
def add(left, right):
return left + right
name = "add"
function = globals().get(name)
if callable(function):
print(function(5, 3))
else:
print(f"Unknown global function: {name}")
8
locals() renvoie l’espace de noms local à l’endroit où il est appelé. Dans une fonction, il peut exposer les noms locaux à cette fonction ; il ne consulte pas les variables locales de l’appelant et ne recherche pas de manière générale dans tout le programme. Son comportement dépend de la portée : il est donc généralement moins clair et moins adapté à la répartition des appels qu’un dictionnaire explicite. Pour en savoir plus sur les dictionnaires, consultez le tutoriel Python sur les dictionnaires.
Pourquoi eval() présente un risque pour la recherche de fonctions
eval() évalue une expression Python ; il ne se contente pas de rechercher un nom de fonction autorisé. Par exemple, eval("add(5, 3)") analyse et évalue un appel en utilisant les noms disponibles dans son environnement d’évaluation. Si une expression contient une entrée non fiable, son évaluation peut exécuter du code avec les privilèges du processus Python. N’utilisez pas eval() pour répartir des appels à partir de noms fournis par des utilisateurs, des fichiers, des requêtes réseau ou d’autres sources non fiables.
Si l’expression provient réellement d’une source fiable et contrôlée, la documentation Python décrit le comportement et les paramètres d’espace de noms de eval(). Pour choisir une fonction ordinaire, une liste d’autorisation sous forme de dictionnaire est plus simple et limite les choix possibles. Analyser ou valider le texte ne rend pas l’évaluation arbitraire aussi sûre qu’un ensemble explicite d’opérations.
Choisir la méthode de recherche adaptée à votre entrée
Utilisez un dictionnaire lorsque les actions disponibles doivent être explicites, en particulier pour les noms fournis par l’utilisateur ou provenant d’une source externe. Utilisez getattr() lorsque l’objet ou le module est déjà choisi et que la chaîne doit sélectionner l’un de ses attributs ; vérifiez la valeur par défaut et le caractère appelable, et tenez compte de la liaison des méthodes. Utilisez globals() uniquement lorsque la recherche au niveau du module est voulue. Utilisez locals() uniquement lorsque le code a délibérément besoin des noms de sa portée locale actuelle, et non comme mécanisme général de répartition des appels. Évitez eval() pour rechercher un nom lorsque l’entrée n’est pas entièrement fiable.
Dans chaque cas, rechercher une fonction et l’invoquer sont deux décisions distinctes : commencez par limiter les fonctions qui peuvent être sélectionnées, puis transmettez des arguments adaptés à leur interface. Pour un ensemble fixe de commandes, cette séparation facilite l’audit et la maintenance du comportement.