Comment puis-je accéder au nom du module ou de la classe en cours d'exécution en cours d'exécution en Python?

StackOverflow https://stackoverflow.com/questions/602846

  •  03-07-2019
  •  | 
  •  

Question

J'aimerais pouvoir extraire de manière dynamique le nom du module ou de la classe en cours d'exécution en cours d'exécution à partir d'un module importé. Voici du code:

foo.py:

def f():
    print __name__

bar.py:

from foo import f

def b(): f()

Cela ne fonctionne évidemment pas car __ nom __ est le nom du module qui contient la fonction. Ce que j'aimerais dans le module foo est le nom du module en cours d'exécution utilisant foo . Donc, dans le cas ci-dessus, ce serait bar mais si tout autre module importé foo , je voudrais que foo ait dynamiquement accès au nom de celui-ci. module.

Modifier: le module inspecter semble prometteur, mais ce n’est pas exactement ce que je cherchais. Ce que j'espérais, c'était une sorte de variable globale ou au niveau de l'environnement à laquelle je pourrais accéder, qui contiendrait le nom du module en cours d'exécution. Non pas que je ne suis pas disposé à parcourir la pile pour trouver cette information - je pensais juste que Python avait peut-être déjà exposé ces données.

Modifier: Voici comment j'essaie de l'utiliser. J'ai deux applications Django différentes qui ont toutes deux besoin de consigner les erreurs dans un fichier. Disons qu'ils s'appellent "AppOne". et "AppTwo". Je souhaite également enregistrer ces fichiers dans un emplacement: " / home / hare / app_logs ". Dans chaque application, à tout moment, j'aimerais pouvoir importer mon module de journalisation et appeler la fonction de journalisation qui écrit la chaîne de journalisation dans un fichier. Toutefois, ce que je voudrais faire est de créer un répertoire sous app_logs , qui correspond au nom de l’application actuelle ("AppOne" ou "AppTwo"), de sorte que les fichiers journaux de chaque application soient placés dans leur répertoire respectif. répertoires de journalisation.

Pour ce faire, j’ai pensé que le meilleur moyen serait que le module d’enregistrement ait accès à une sorte de variable globale indiquant le nom de l’application actuelle car il est responsable de la connaissance de l’emplacement du répertoire de journalisation parent et de la création. le répertoire de journalisation de l'application s'il n'existe pas encore.

Était-ce utile?

La solution

D'après le commentaire - pas la question.

  

Je suis simplement curieux de voir si ce que j'essaie de faire est possible.

La réponse à "est-ce possible" est toujours "oui". Toujours. À moins que votre question ne concerne un voyage dans le temps, une anti-gravité ou un mouvement perpétuel.

Étant donné que la réponse est toujours "oui", votre question est mal formulée. La vraie question est "quel bon moyen pour que mon module de journalisation connaisse le nom du client?" ou quelque chose comme ça.

La réponse est "Acceptez-le en tant que paramètre". Ne vous embêtez pas avec l'inspection ou la recherche de globaux mystérieux ou d'autres astuces.

Suivez simplement le modèle de conception de logging.getLogger () et utilisez des enregistreurs nommés explicitement. Un idiome courant est le suivant

logger= logging.getLogger( __name__ )

Cela gère presque tous les noms de journaux parfaitement.

Autres conseils

Ceci devrait fonctionner pour référencer le module actuel:

import sys
sys.modules[__name__]

Le " module en cours d'exécution " clairement est foo, car c’est ce qui contient la fonction en cours d’exécution - je pense une meilleure description de ce que vous voulez est le module de l’appelant immédiat de foo (qui peut être lui-même foo si vous appelez af () depuis une fonction appelée foo par une fonction dans la barre. La distance à laquelle vous voulez monter dépend de ce que vous voulez faire.

Dans tous les cas, en supposant que vous souhaitiez appeler immédiatement, vous pouvez l'obtenir en remontant la pile d'appels. Cela peut être accompli en appelant sys._getframe , avec le nombre approprié de niveaux à marcher.

def f():
    caller = sys._getframe(1)  # Obtain calling frame
    print "Called from module", caller.f_globals['__name__']

[Modifier] : en réalité, utilisez le inspecter . module comme suggéré ci-dessus est probablement une manière plus propre d’obtenir le cadre de pile. Le code équivalent est:

def f():
    caller = inspect.currentframe().f_back
    print "Called from module", caller.f_globals['__name__']

(sys._getframe est documenté comme étant à usage interne - le module inspecter est une API plus fiable)

Je pense que vous voulez utiliser le module inspect pour inspecter le pile d'exécution python. Consultez ce tutoriel . Je pense que cela fournit un exemple presque exact de ce que vous voulez faire.

__ fichier __ est le chemin du module actuel de l'appel.

Pour obtenir une référence à la " __ main __ " module dans un autre:

import sys
sys.modules['__main__']

Pour obtenir ensuite le chemin du fichier du module, qui inclut son nom:

sys.modules['__main__'].__file__

Si compris dans le " __ main __ " module, utilisez simplement: __ fichier __

Pour obtenir uniquement le nom du fichier à partir du chemin du fichier:

import os
os.path.basename(file_path)

Pour séparer le nom du fichier de son extension:

file_name.split(".")[0]

Pour obtenir le nom d'une instance de classe:

instance.__class__.__name__

Pour obtenir le nom d'une classe:

class.__name__

Je ne crois pas que ce soit possible car cela sort du champ de foo . foo n'aura conscience que de sa portée interne car il peut être appelé par d'innombrables autres modules et applications.

L'utilisation de __ fichier __ seul vous donne un chemin relatif pour le module principal et un chemin absolu pour les modules importés. Etant conscients de cela, nous pouvons obtenir le fichier de module constamment dans les deux cas avec un peu d'aide de nos outils os.path .

Pour le nom de fichier uniquement, utilisez __ fichier __. split (os.path.sep) [- 1] .

Pour le chemin complet, utilisez os.path.abspath (__ fichier __) .

Démo:

/tmp $ cat f.py
from pprint import pprint
import os
import sys

pprint({
    'sys.modules[__name__]': sys.modules[__name__],
    '__file__': __file__,
    '__file__.split(os.path.sep)[-1]': __file__.split(os.path.sep)[-1],
    'os.path.abspath(__file__)': os.path.abspath(__file__),
})

/tmp $ cat i.py
import f

Résultats:

## on *Nix ##

/tmp $ python3 f.py
{'sys.modules[__name__]': <module '__main__' from 'f.py'>,
 '__file__': 'f.py',
 '__file__.split(os.path.sep)[-1]': 'f.py',
 'os.path.abspath(__file__)': '/tmp/f.py'}

/tmp $ python3 i.py
{'sys.modules[__name__]': <module 'f' from '/tmp/f.pyc'>,
 '__file__': '/tmp/f.pyc',
 '__file__.split(os.path.sep)[-1]': 'f.pyc',
 'os.path.abspath(__file__)': '/tmp/f.pyc'}

## on Windows ##

PS C:\tmp> python3.exe f.py
{'sys.modules[__name__]': <module '__main__' from 'f.py'>,
 '__file__': 'f.py',
 '__file__.split(os.path.sep)[-1]': 'f.py',
 'os.path.abspath(__file__)': 'C:\\tools\\cygwin\\tmp\\f.py'}

PS C:\tmp> python3.exe i.py
{'sys.modules[__name__]': <module 'f' from 'C:\\tools\\cygwin\\tmp\\f.py'>,
 '__file__': 'C:\\tools\\cygwin\\tmp\\f.py',
 '__file__.split(os.path.sep)[-1]': 'f.py',
 'os.path.abspath(__file__)': 'C:\\tools\\cygwin\\tmp\\f.py'}

Si vous souhaitez supprimer la ".py" de la fin, vous pouvez le faire facilement. (Mais n'oubliez pas que vous pouvez utiliser un '.pyc' à la place.)

Cela fait un certain temps que je n'ai pas python, mais je pense que vous pouvez accéder aux globaux et locaux d'un appelant via son traceback .

Si vous souhaitez uniquement le nom du fichier:

file_name = __file__.split("/")[len(__file__.split("/"))-1]

Pour obtenir le module de fichier actuel, contenant le dossier, voici ce qui a fonctionné pour moi:

 import os
 parts = os.path.splitext(__name__)
 module_name = parts[len(parts) - 2]
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top