Récupère le nom du module de la fonction appelante en Python

Supposons que myapp/foo.py contient:

def info(msg):
    caller_name = ????
    print '[%s] %s' % (caller_name, msg)

Et myapp/bar.py contient:

import foo
foo.info('Hello') # => [myapp.bar] Hello

Je veux que caller_name soit défini sur l'attribut __name__ du module des fonctions appelantes (qui est 'myapp.foo') dans ce cas. Comment cela peut-il être fait?

72
demandé sur Sridhar Ratnakumar 2009-07-08 04:30:47

3 réponses

Consultez le module inspect:

inspect.stack() retourne les informations de la pile.

Dans une fonction, inspect.stack()[1] retournera la pile de votre appelant. De là, vous pouvez obtenir plus d'informations sur le nom de la fonction de l'appelant, le module, etc.

Voir les documents pour plus de détails:

Http://docs.python.org/library/inspect.html

En outre, Doug Hellmann a une belle écriture du module inspect dans son PyMOTW série:

Http://pymotw.com/2/inspect/index.html#module-inspect

EDIT: voici un code qui fait ce que vous voulez, je pense:

def info(msg):
    frm = inspect.stack()[1]
    mod = inspect.getmodule(frm[0])
    print '[%s] %s' % (mod.__name__, msg)
97
répondu ars 2014-11-02 12:47:10

Confronté à un problème similaire, j'ai trouvé que sys._current_frames () du module sys contient des informations intéressantes qui peuvent vous aider, sans avoir besoin d'importer inspect, au moins dans des cas d'utilisation spécifiques.

>>> sys._current_frames()
{4052: <frame object at 0x03200C98>}

Vous pouvez ensuite "monter" en utilisant f_back:

>>> f = sys._current_frames().values()[0]
>>> # for python3: f = list(sys._current_frames().values())[0]

>>> print f.f_back.f_globals['__file__']
'/base/data/home/apps/apricot/1.6456165165151/caller.py'

>>> print f.f_back.f_globals['__name__']
'__main__'

Pour le nom de fichier, vous pouvez également utiliser F. f_back. f_code. co_filename, comme suggéré par Mark Roddy ci-dessus. Je ne suis pas sûr des limites et des mises en garde de cette méthode (plusieurs threads seront probablement un problème), mais j'ai l'intention de l'utiliser dans mon cas.

18
répondu Louis LC 2018-05-06 18:37:14

Je ne recommande pas de le faire, mais vous pouvez atteindre votre objectif avec la méthode suivante:

def caller_name():
    frame=inspect.currentframe()
    frame=frame.f_back.f_back
    code=frame.f_code
    return code.co_filename

Ensuite, mettez à jour votre méthode existante comme suit:

def info(msg):
    caller = caller_name()
    print '[%s] %s' % (caller, msg)
2
répondu Mark Roddy 2009-07-08 01:32:12