Disons que j'ai une fonction foo
:
bar = lambda: foo
et je passe cette fonction ci-dessus à la fonction lambda en l'associant à une variable. p >
def foo(): print('something')
Donc, si j'ai l'objet bar
, comment puis-je extraire le nom de la fonction qui lui a été passé, c'est-à-dire foo
?
J'ai essayé de lister toutes les méthodes de cet objet bar
en utilisant dir (bar)
, je n'ai pas trouvé grand chose pour extraire le résultat souhaité.
3 Réponses :
Vous ne pouvez pas faire cela directement, mais vous pouvez appeler bar
, qui renvoie foo
, et vérifier son attribut __name__
:
>>> bar().__name__ 'foo'
Si vous ne souhaitez pas appeler la fonction pour obtenir son nom (comme suggéré dans d'autres réponses), vous pouvez inspecter
votre fonction pour obtenir le code, et à partir de là, travaillez votre chemin pour obtenir le nom de la fonction passée:
import inspect def foo(x, y, z): print('something') bar = lambda x, y, z: foo(x, y, z) func_code = inspect.getsource(bar) print(func_code) passed_function = func_code.split('(')[0].split(' ')[-1] print(passed_function)
Sortie:
bar = lambda: foo
Et trouver la fonction fournie ne devrait pas être compliqué, c'est-à-dire :
func_code = inspect.getsource(bar) passed_function = func_code.split(' ')[-1] print(passed_function)
Sortie:
toto
Même si vous avez plusieurs arguments, vous pouvez extraire le nom de la fonction fournie:
def foo(): print('something') bar = lambda: foo print(inspect.getsource(bar))
Sortie:
toto
C'est incroyablement fragile, par exemple je pourrais écrire un bar = lambda: foo
ou bar = lambda x, y, z: foo (x, y, z)
et ça ' d échoue, même si la variable est exactement la même.
Je comprends votre point de vue, mais c'est un problème différent. Cela semble fragile parce que c'est un exemple, mais le nom de la fonction d'analyse et d'extraction est la façon dont outils d'analyse statique fonctionne.
Si vous exécutiez la source via ast.parse
ou similaire, alors oui, ce serait possible mais je doute que les outils d'analyse statique reposent sur le fractionnement sur des espaces.
Le fractionnement @Holloway sur les espaces en était un exemple; exemples est une conceptualisation non-exhaustive représentative d'un plus grand groupe (dans ce cas, analyse). Les outils d'analyse statique ne reposent pas sur cela, mais ils le font analyser le code ! donc: compris la critique, pas le cas.
Pourquoi utilisez-vous bar = lambda: foo
au lieu de simplement bar = foo
?
Le lambda
renvoie un objet foo
ce qui signifie que vous devez faire quelque chose comme:
def foo(x, y, z): print(x, y, z) y = 3 z = 2 bar = lambda x, y=y, z=z: foo(x, y, z) # now to call foo: bar(1) # 1 3 2 # but printing the name is this case is more tricky since the # lambda isn't return the function object but the return value # of that function. # Thus you would need to use inspect like the answer below.
Les fonctions sont des objets de première classe en python donc vous ne pas besoin de lambda pour quelque chose d'aussi simple.
bar = foo print(bar.__name__) # foo # now to call foo: bar()
Ce serait une autre histoire si vous vouliez passer des arguments par défaut:
bar = lambda: foo # now to call foo: bar()()
bar (1) .__ name__
ne fonctionnerait pas avec cet exemple car il lirait l'attribut __name__
sur tout ce que foo
ne renvoie pas foo
lui-même (dans ce cas Aucun
).
Notez que cela n'a rien à voir avec les fonctions d'ordre supérieur ou les lambdas, c'est juste le moyen d'obtenir le nom de quelque chose en Python.
Vous ne passez pas
foo
dans une fonction lambda ici. Vous écrivez une fonction lambda qui la renvoie. Qu'essayez-vous de faire?pourquoi utilisez-vous un lambda qui n'a pas de paramètres et renvoie
toto
. Utilisez simplementfoo
?@Pynchia c'est juste et un exemple d'exemple que j'ai montré le cas d'utilisation réel est un peu complexe et bien sûr je passe un argument.
@Holloway en rapport avec cette réponse, stackoverflow.com/a/45279060/5964750
Je pense que vous pourriez mettre à jour la question pour mieux correspondre à votre cas d'utilisation. Si vous utilisez réellement
bar = lambda x: foo (x)
, il n'y a aucun moyen d'extraire le nomfoo
de bar (sauf peut-être via un hack dis / ast) .@Holloway J'ai une combinaison de fonctions passées avec le post_save d'une instance de modèle différente. Maintenant, je veux écrire des cas de test pour vérifier que des conditions telles que
foo1
seront passées à l'intérieur de l'événement post_save du modèleM1
post save,foo2
sera passé pour après l'enregistrement du modèleM2
et ainsi de suite.@ Error-SyntacticalRemorse, je suis d'accord que l'exemple est un peu étrange mais
bar = lambda: foo
etbar = foo
ne sont pas les mêmes.@Holloway Je suis d'accord qu'ils sont légèrement différents. Le lambda renvoie
foo
comme appelable qui doit être appelé à nouveau. Cela n'est presque jamais nécessaire, sauf si vous tapez des variables par défaut.