Appeler une fonction d'un module en utilisant son nom (une chaîne)
Quelle est la meilleure façon d'appeler une fonction donnée par une chaîne avec le nom de la fonction dans un programme Python? Par exemple, disons que j'ai un module foo
, et j'ai une chaîne dont le contenu est "bar"
. Quelle est la meilleure façon d'appeler foo.bar()
?
j'ai besoin d'obtenir la valeur de retour de la fonction, c'est pourquoi je ne l'utilise pas seulement eval
. J'ai compris comment le faire en utilisant eval
pour définir une fonction de temp renvoie le résultat de cet appel de fonction, mais j'espère qu'il y a une façon plus élégante de le faire.
10 réponses
, selon le module foo
et la méthode bar
:
import foo
method_to_call = getattr(foo, 'bar')
result = method_to_call()
dans la mesure où cela va, les lignes 2 et 3 peuvent être compressées comme suit:
result = getattr(foo, 'bar')()
si ça fait plus de sens pour votre cas d'utilisation. Vous pouvez utiliser getattr
de cette façon sur les méthodes liées aux instances de classe, les méthodes au niveau du module, les méthodes de classe... la liste est longue.
la solution de Patrick est probablement la plus propre. Si vous avez besoin de choisir dynamiquement le module ainsi, vous pouvez l'importer comme:
module = __import__('foo')
func = getattr(module, 'bar')
func()
une simple contribution. Si la classe que nous avons besoin d'instance est dans le même fichier, nous pouvons utiliser quelque chose comme ceci:
# Get class from globals and create an instance
m = globals()['our_class']()
# Get the function (from the instance) that we need to call
func = getattr(m, 'function_name')
# Call it
func()
par exemple:
class A:
def __init__(self):
pass
def sampleFunc(self, arg):
print('you called sampleFunc({})'.format(arg))
m = globals()['A']()
func = getattr(m, 'sampleFunc')
func('sample arg')
# Sample, all on one line
getattr(globals()['A'](), 'sampleFunc')('sample arg')
et, si ce n'est pas une classe:
def sampleFunc(arg):
print('you called sampleFunc({})'.format(arg))
globals()['sampleFunc']('sample arg')
avec une chaîne de caractères, avec un chemin python complet vers une fonction, c'est ainsi que j'ai obtenu le résultat de ladite fonction:
import importlib
function_string = 'mypackage.mymodule.myfunc'
mod_name, func_name = function_string.rsplit('.',1)
mod = importlib.import_module(mod_name)
func = getattr(mod, func_name)
result = func()
la réponse (j'espère) personne n'a jamais voulu
Eval comme le comportement
getattr(locals().get("foo") or globals().get("foo"), "bar")()
pourquoi ne pas ajouter importation automatique
getattr(
locals().get("foo") or
globals().get("foo") or
__import__("foo"),
"bar")()
dans le cas où nous avons des dictionnaires supplémentaires que nous voulons vérifier
getattr(next((x for x in (f("foo") for f in
[locals().get, globals().get,
self.__dict__.get, __import__])
if x)),
"bar")()
il faut aller plus loin
getattr(next((x for x in (f("foo") for f in
([locals().get, globals().get, self.__dict__.get] +
[d.get for d in (list(dd.values()) for dd in
[locals(),globals(),self.__dict__]
if isinstance(dd,dict))
if isinstance(d,dict)] +
[__import__]))
if x)),
"bar")()
la meilleure réponse selon la FAQ de programmation Python serait:
functions = {'myfoo': foo.bar}
mystring = 'myfoo'
if mystring in functions:
functions[mystring]()
Le principal avantage de cette technique est que les chaînes n'ont pas besoin de faire correspondre les noms des fonctions. Il s'agit également de la technique principale utilisée pour émuler une construction de cas
pour ce que ça vaut, si vous aviez besoin de passer le nom de la fonction (ou de la classe) et le nom de l'application comme chaîne de caractères, alors vous pourriez faire ceci:
myFnName = "MyFn"
myAppName = "MyApp"
app = sys.modules[myAppName]
fn = getattr(app,myFnName)
rien de ce qui a été suggéré m'a aidé. J'ai fait découvrir ce bien.
<object>.__getattribute__(<string name>)(<params>)
j'utilise python 2.66
Espérons que cette aide
essayez ceci. Bien que cela utilise encore eval, il ne l'utilise que pour invoquer la fonction du contexte actuel . Ensuite, vous avez la fonction réelle à utiliser comme vous le souhaitez.
le principal avantage pour moi de ceci est que vous obtiendrez toutes les erreurs liées à eval au point d'invoquer la fonction. Ensuite, vous obtiendrez seulement les erreurs liées à la fonction lorsque vous appelez.
def say_hello(name):
print 'Hello {}!'.format(name)
# get the function by name
method_name = 'say_hello'
method = eval(method_name)
# call it like a regular function later
args = ['friend']
kwargs = {}
method(*args, **kwargs)