2
votes

Comment extraire le nom de la fonction qui a été passé en argument à la fonction lambda de Python?

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é.


9 commentaires

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 simplement foo ?


@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 nom foo 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èle M1 post save, foo2 sera passé pour après l'enregistrement du modèle M2 et ainsi de suite.


@ Error-SyntacticalRemorse, je suis d'accord que l'exemple est un peu étrange mais bar = lambda: foo et bar = 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.


3 Réponses :


4
votes

Vous ne pouvez pas faire cela directement, mais vous pouvez appeler bar , qui renvoie foo , et vérifier son attribut __name__ :

>>> bar().__name__
'foo'


0 commentaires

-1
votes

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


4 commentaires

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.



0
votes

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()()


1 commentaires

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 ).