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