Come posso accedere al modulo di esecuzione corrente o al nome della classe in Python?

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

  •  03-07-2019
  •  | 
  •  

Domanda

Vorrei essere in grado di recuperare dinamicamente il modulo di esecuzione corrente o il nome della classe da un modulo importato. Ecco un po 'di codice:

foo.py:

def f():
    print __name__

bar.py:

from foo import f

def b(): f()

Questo ovviamente non funziona poiché __name__ è il nome del modulo che contiene la funzione. Quello a cui vorrei accedere all'interno del modulo foo è il nome dell'attuale modulo in esecuzione che utilizza foo . Quindi nel caso sopra sarebbe bar ma se qualsiasi altro modulo importasse foo vorrei che foo potesse accedere dinamicamente al nome di quello modulo.

Modifica: Il modulo inspect sembra abbastanza promettente ma non è esattamente quello che stavo cercando. Quello che speravo fosse una sorta di variabile globale o di livello ambientale a cui potessi accedere che contenesse il nome del modulo di esecuzione corrente. Non che non sia disposto a attraversare lo stack per trovare quelle informazioni - ho solo pensato che Python potrebbe aver già esposto quei dati.

Modifica: Ecco come sto cercando di utilizzare questo. Ho due diverse applicazioni Django che devono entrambe registrare errori nel file. Diciamo che sono chiamati " AppOne " e "AppTwo". Ho anche un posto in cui vorrei registrare questi file: " / home / hare / app_logs " ;. In ogni applicazione in qualsiasi momento vorrei poter importare il mio modulo logger e chiamare la funzione di registro che scrive la stringa di registro su file. Tuttavia, ciò che vorrei fare è creare una directory in app_logs che sia il nome dell'applicazione corrente (" AppOne " o " AppTwo ") in modo che i file di registro di ciascuna applicazione andranno nei rispettivi directory di log.

Per fare questo ho pensato che il modo migliore sarebbe che il modulo logger avesse accesso a una sorta di variabile globale che denota il nome dell'applicazione corrente in quanto è responsabile della conoscenza della posizione della directory di registrazione principale e della creazione la directory di registrazione dell'applicazione se non esiste ancora.

È stato utile?

Soluzione

Dal commento, non dalla domanda.

  

Sono semplicemente curioso di vedere se ciò che sto cercando di fare è possibile.

La risposta a " è possibile " è sempre "sì". Sempre. A meno che la tua domanda non riguardi il viaggio nel tempo, l'antigravità o il moto perpetuo.

Poiché la risposta è sempre "sì", la tua domanda non è chiara. La vera domanda è "qual è il modo migliore per far conoscere al mio modulo di registrazione il nome del client?" o qualcosa del genere.

La risposta è " Accettala come parametro. " Non scherzare con l'ispezione o la ricerca di misteriosi globi o altri trucchi.

Segui semplicemente il modello di progettazione di logging.getLogger () e usa logger con nome esplicito. Un linguaggio comune è il seguente

logger= logging.getLogger( __name__ )

Gestisce perfettamente quasi tutti i nomi dei log.

Altri suggerimenti

Questo dovrebbe funzionare per fare riferimento al modulo corrente:

import sys
sys.modules[__name__]

Il modulo "attualmente in esecuzione" chiaramente è foo, poiché questo è ciò che contiene la funzione attualmente in esecuzione - penso che una migliore descrizione di ciò che vuoi sia il modulo del chiamante immediato di foo (che potrebbe essere esso stesso se stai chiamando af () da una funzione in foo chiamata da una funzione nella barra. La misura in cui vuoi salire dipende da cosa desideri.

In ogni caso, supponendo che tu voglia il chiamante immediato, puoi ottenerlo salendo nello stack di chiamate. Ciò può essere ottenuto chiamando sys._getframe , con il numero appropriato di livelli da percorrere.

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

[Modifica] : in realtà, utilizzando inspect Il modulo come suggerito sopra è probabilmente un modo più pulito di ottenere il frame dello stack. Il codice equivalente è:

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

(sys._getframe è documentato come per uso interno - il modulo inspect è un'API più affidabile)

Penso che ciò che vuoi usare sia il inspect , per ispezionare il stack di runtime python. Dai un'occhiata a questo tutorial . Penso che fornisca un esempio quasi esatto di ciò che vuoi fare.

__file__ è il percorso del modulo corrente in cui viene effettuata la chiamata.

Per ottenere un riferimento a " __ main __ " modulo in un altro:

import sys
sys.modules['__main__']

Per ottenere quindi il percorso del file del modulo, che include il suo nome:

sys.modules['__main__'].__file__

Se all'interno di " __ main __ " modulo, basta usare: __file__

Per ottenere solo il nome del file dal percorso del file:

import os
os.path.basename(file_path)

Per separare il nome del file dalla sua estensione:

file_name.split(".")[0]

Per ottenere il nome di un'istanza di classe:

instance.__class__.__name__

Per ottenere il nome di una classe:

class.__name__

Non credo sia possibile poiché non rientra nell'ambito di foo . foo sarà a conoscenza del suo ambito interno poiché potrebbe essere chiamato da innumerevoli altri moduli e applicazioni.

L'uso del __file__ da solo fornisce un percorso relativo per il modulo principale e un percorso assoluto per i moduli importati. Consapevole di ciò, possiamo ottenere costantemente il file del modulo in entrambi i modi con un piccolo aiuto dai nostri strumenti os.path .

Per il nome file utilizzare solo __file __. split (os.path.sep) [- 1] .

Per il percorso completo utilizzare os.path.abspath (__ file__) .

Demo:

/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

Risultati:

## 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'}

Se vuoi eliminare '.py' dalla fine, puoi farlo facilmente. (Ma non dimenticare che puoi eseguire un '.pyc' invece.)

È passato un po 'di tempo da quando ho fatto Python, ma credo che tu possa avere accesso ai globi e ai locali di un chiamante tramite traceback .

Se vuoi solo il nome del file:

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

Per ottenere il modulo di file corrente, contenente la cartella, ecco cosa ha funzionato per me:

 import os
 parts = os.path.splitext(__name__)
 module_name = parts[len(parts) - 2]
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top