Wie kann ich die aktuellen Ausführung Modul oder Klassennamen in Python zugreifen?
Frage
Ich möchte in der Lage sein, dynamisch aus einem importierten Modul die aktuelle Ausführung Modul oder Klassenname abzurufen. Hier ist ein Code:
foo.py:
def f():
print __name__
bar.py:
from foo import f
def b(): f()
Das ist offensichtlich nicht funktioniert als __name__
der Name des Moduls ist, die die Funktion enthält. Was ich möchte, Zugang zum Innern des foo
Modul sein, ist der Name des aktuellen Ausführungsmodul, das foo
verwendet wird. So im Fall darüber bar
werden würde, aber wenn ein anderes Modul foo
importiert würde ich foo
gerne dynamisch Zugang haben, um den Namen des Moduls.
Edit: Das inspect
Modul sieht sehr vielversprechend, aber es ist nicht genau das, was ich suchte. Was ich erhofft war eine Art globalen oder Umwelt-Level-Variable, die ich, dass der Namen des aktuellen Ausführungsmodul enthalten würde zugreifen konnte. Nicht, dass ich bin nicht bereit, den Stapel zu durchqueren, diese Informationen zu finden - ich dachte nur, dass Python ausgesetzt hat, dass Daten bereits
Edit: Hier ist, wie ich versuche, diese zu verwenden. Ich habe zwei verschiedene Django-Anwendungen, die beide müssen Fehler protokollieren Datei. Lassen Sie uns sagen, dass sie „AppOne“ und „AppTwo“ bezeichnet werden. Ich habe auch einen Ort, an den Ich mag würde, diese Dateien protokollieren: „/home/hare/app_logs
“. Bei jeder Anwendung an jedem beliebigen Punkt würde Ich mag Lage sein, mein Logger Modul zu importieren und die Log-Funktion aufrufen, die die Log-String-Datei schreibt. Aber was würde ich tun möchte, ist ein Verzeichnis unter app_logs
erstellen, die die Namen der aktuellen Anwendung ( „AppOne“ oder „AppTwo“), so dass jede Protokolldateien der Anwendung in ihren jeweiligen Protokoll Verzeichnisse gehen.
Um dies zu tun, dachte ich, dass der beste Weg wäre, der Logger-Modul Zugang zu haben, um eine Art globale Variable, die der aktuellen Anwendung Namen bezeichnet, wie es für die Kenntnis der Position des übergeordneten Protokollverzeichnis verantwortlich ist und die Schaffung von die Logging-Verzeichnis der Anwendung, wenn es noch nicht vorhanden ist.
Lösung
Aus dem Kommentar -. Nicht die Frage
Ich bin einfach gespannt, ob das, was ich versuche möglich zu tun ist.
Die Antwort auf „ist es möglich,“ immer „ja“. Immer. Es sei denn, Ihre Frage beinhaltet eine Zeitreise, Anti-Schwerkraft oder ständige Bewegung.
Da die Antwort ist immer „ja“ lautet, Ihre Frage ist schlecht ausgebildet. Die eigentliche Frage lautet: „Was ist ein guter Weg, um meinen Logging-Modul den Namen des Kunden kennt zu haben?“ oder so ähnlich.
Die Antwort ist „Nehmen Sie es als Parameter.“ Verwirren Sie nicht um mit Inspektion oder auf der Suche nach einem geheimnisvollen Globals oder anderen Tricks.
Folgen Sie einfach dem Designmuster von logging.getLogger () und explizit genannten Logger verwenden. Ein gemeinsames Idiom ist die folgende
logger= logging.getLogger( __name__ )
Das Griffe fast alle Log-Namensgebung perfekt.
Andere Tipps
Dies sollte das aktuelle Modul zur Referenzierung arbeiten:
import sys
sys.modules[__name__]
Die „aktuell ausgeführte Modul“ eindeutig ist foo, wie das ist, was die Funktion enthält derzeit läuft - ich denke, eine bessere Beschreibung, was Sie wollen, ist das Modul der sofortigen Anrufers foo (die selbst foo sein kann, wenn Sie anrufen af () aus einer Funktion in foo durch eine Funktion in bar genannt. Wie weit Sie hängt davon ab, gehen will, was Sie wollen, dass diese für.
In jedem Fall vorausgesetzt, Sie den unmittelbaren Aufrufer möchten, können Sie diese erhalten, indem man den Call-Stack Fuß nach oben. Dies kann durch den Aufruf von sys._getframe
erreicht werden, mit der aprropriate Anzahl der Ebenen gehen.
def f():
caller = sys._getframe(1) # Obtain calling frame
print "Called from module", caller.f_globals['__name__']
[Bearbeiten] : Eigentlich die zu inspizieren Modul, wie oben vorgeschlagen, ist wahrscheinlich ein sauberer Weg, um den Stapelrahmen zu erhalten. Der entsprechende Code ist:
def f():
caller = inspect.currentframe().f_back
print "Called from module", caller.f_globals['__name__']
(sys._getframe wird dokumentiert, wie für den internen Gebrauch zu sein - das überprüfen Modul ist ein zuverlässiger API)
Ich denke, was Sie verwenden möchten, ist die Modul inspizieren, inspizieren die python-Laufzeit-Stack. Schauen Sie sich diese Tutorial . Ich denke, es gibt ein fast genau Beispiel dafür, was Sie tun mögen.
__file__
ist der Pfad des aktuellen Moduls der Anruf erfolgt.
Um einen Verweis auf das "__main__" -Modul, wenn sie in ein anderes zu erhalten:
import sys
sys.modules['__main__']
dann um das Modul des Dateipfad zu erhalten, die ihren Namen enthält:
sys.modules['__main__'].__file__
Wenn im "__main__" -Modul, verwenden Sie einfach: __file__
Um nur die Dateinamen aus dem Dateipfad zu erhalten:
import os
os.path.basename(file_path)
Um die Dateinamen von seiner Erweiterung zu trennen:
file_name.split(".")[0]
Um den Namen einer Klasseninstanz zu erhalten:
instance.__class__.__name__
Um den Namen einer Klasse zu erhalten:
class.__name__
Ich glaube nicht, das möglich ist, da diese aus foo
Anwendungsbereich ist. foo nur bewusst sein, ihren internen Anwendungsbereich, da es durch unzählige andere Module und Anwendungen aufgerufen werden wird.
Mit __file__
allein gibt Ihnen einen relativen Pfad für das Hauptmodul und einen absoluten Pfad für importierte Module. Im Bewusstsein diesen können wir die Moduldatei ständig oder so mit einer wenig Hilfe von unseren os.path
Tool.
Für Dateinamen nur __file__.split(os.path.sep)[-1]
verwenden.
Für eine vollständige Pfad Verwendung 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
Ergebnisse:
## 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'}
Wenn Sie das ‚.py‘ abzustreifen wollen über das Ende, können Sie das leicht tun. (Aber vergessen Sie nicht, dass Sie stattdessen ein ‚.pyc‘ laufen.)
Es ist schon eine Weile her, seit ich Python getan habe, aber ich glaube, dass Sie Zugriff auf die globalen Variablen und Einheimischer von einem Anrufer über die Zurückverfolgungs .
Wenn Sie nur den Namen der Datei wollen:
file_name = __file__.split("/")[len(__file__.split("/"))-1]
Um den aktuellen Datei-Modul zu erhalten, einen Ordner enthält, hier ist das, was für mich gearbeitet:
import os
parts = os.path.splitext(__name__)
module_name = parts[len(parts) - 2]