So erhalten Sie einen Verweis auf die Attribute des aktuellen Moduls in Python

119

Was ich versuche, würde in der Befehlszeile so aussehen:

>>> import mymodule
>>> names = dir(mymodule)

Wie kann ich einen Verweis auf alle den Namen bekommen definiert in mymodulevon innen heraus mymoduleselbst?

Etwas wie das:

# mymodule.py
names = dir(__thismodule__)
guillermooo
quelle
Bitte überprüfen Sie auch stackoverflow.com/questions/3281300/…
ksridhar

Antworten:

135

Verwenden Sie einfach Globals ()

globals () - Gibt ein Wörterbuch zurück, das die aktuelle globale Symboltabelle darstellt. Dies ist immer das Wörterbuch des aktuellen Moduls (innerhalb einer Funktion oder Methode ist dies das Modul, in dem es definiert ist, nicht das Modul, von dem es aufgerufen wird).

http://docs.python.org/library/functions.html#globals

Maciej Pasternacki
quelle
4
Gibt es eine Möglichkeit, auf die gloabals () des aufrufenden Moduls anstatt auf das definierende Modul zuzugreifen?
dimo414
9
Sie können versuchen, die Globals des Anrufers aus dem Traceback-Modul ( docs.python.org/library/traceback.html ) abzurufen , aber dies betritt das Gebiet der dunklen Magie. Ich weiß nicht, was Sie versuchen, aber vielleicht möchten Sie Ihr Design überdenken, wenn Sie das brauchen.
Maciej Pasternacki
Ein klassischer Fall von "Ich brauche X (um Y zu erledigen) -> Du brauchst kein X, du brauchst Z". Ich brauche aber X! Nichts für ungut, ich finde das nur amüsant und die am meisten
gewählte
Es ist wichtig zu beachten, dass globals () ein falsches Ergebnis zurückgeben kann, da dies vom Kontext abhängt, in dem es aufgerufen wird. Wenn Sie beispielsweise eine Klassenfunktion aufrufen, wird der mit der Klasse verknüpfte globale Kontext zurückgegeben, nicht der aktuelle Modulkontext, was sich erheblich unterscheidet. Selbst wenn Sie eine freie Funktion aufrufen, kann dies einen globalen Modulkontext eines anderen Moduls zurückgeben, abhängig davon, wie die Funktion importiert wurde.
Andry
163

Wie bereits erwähnt, erhalten Sie mit globals ein Wörterbuch im Gegensatz zu dir (), das eine Liste der im Modul definierten Namen enthält. Die Art und Weise, wie ich das normalerweise sehe, ist wie folgt:

import sys
dir(sys.modules[__name__])
Jamesls
quelle
2
Ich wollte einen Kommentar hinzufügen, dass dies für das ' Haupt' -Modul (wie das am Terminal ausgeführte Modul heißt) nicht funktionieren würde, da dies nicht in sys.modules aufgeführt zu sein scheint - aber es funktioniert tatsächlich :)
Markm
Es scheint jedoch nicht von ipdb aus zu funktionieren (fügen Sie "import ipdb; ipdb.set_trace ()" in Ihre Datei ein).
Gatoatigrado
9
Ausgezeichnet! Dadurch konnte ich nur die Dokumentzeichenfolge des aktuellen Moduls als Verwendungsnachricht verwenden sys.modules[__name__].__doc__.
George
Und um super hacky zu werden. operators.attrgetter('module.attribute')(sys.modules[__name__])- Weißt du, wenn du verrückte Dinge tust, sagen dir die Leute, du sollst keine Pakete dynamisch aus Strings importieren und diese dann von Affen patchen, während du nicht in einer Klasse
Casey
2
Für alle, die einen Kommentar von George lesen: sys.modules[__name__].__doc__== __doc__wie dies im aktuellen Namespace definiert ist. Das Abrufen des Modulobjekts für den Zugriff auf seine eigenen Attribute ist daher nicht erforderlich.
Oliver Bestwalter
1

Es mag spät sein zu antworten, aber ich habe nicht die richtige Antwort für mich gefunden. Die naheliegendste und präziseste Lösung (schneller als inspect.stack()) in der Python 3.7.x:

  # search for first module in the stack
  stack_frame = inspect.currentframe()
  while stack_frame:
    print('***', stack_frame.f_code.co_name, stack_frame.f_code.co_filename, stack_frame.f_lineno)
    if stack_frame.f_code.co_name == '<module>':
      if stack_frame.f_code.co_filename != '<stdin>':
        caller_module = inspect.getmodule(stack_frame)
      else:
        # piped or interactive import
        caller_module = sys.modules['__main__']
      if not caller_module is None:
        #... do something here ...
      break
    stack_frame = stack_frame.f_back

Vorteile :

  • Präziser als globals()Methode.
  • Hängt nicht von den Stack-Zwischenframes ab, die zum Beispiel durch Hooking oder durch die 3dparty-Tools wie pytest:
*** foo ... ..
*** boo ... ..
*** runtest c:\python\x86\37\lib\site-packages\xonsh\pytest_plugin.py 58
*** pytest_runtest_call c:\python\x86\37\lib\site-packages\_pytest\runner.py 125
*** _multicall c:\python\x86\37\lib\site-packages\pluggy\callers.py 187
*** <lambda> c:\python\x86\37\lib\site-packages\pluggy\manager.py 86
*** _hookexec c:\python\x86\37\lib\site-packages\pluggy\manager.py 92
*** __call__ c:\python\x86\37\lib\site-packages\pluggy\hooks.py 286
*** <lambda> c:\python\x86\37\lib\site-packages\_pytest\runner.py 201
*** from_call c:\python\x86\37\lib\site-packages\_pytest\runner.py 229
*** call_runtest_hook c:\python\x86\37\lib\site-packages\_pytest\runner.py 201
*** call_and_report c:\python\x86\37\lib\site-packages\_pytest\runner.py 176
*** runtestprotocol c:\python\x86\37\lib\site-packages\_pytest\runner.py 95
*** pytest_runtest_protocol c:\python\x86\37\lib\site-packages\_pytest\runner.py 80
*** _multicall c:\python\x86\37\lib\site-packages\pluggy\callers.py 187
*** <lambda> c:\python\x86\37\lib\site-packages\pluggy\manager.py 86
*** _hookexec c:\python\x86\37\lib\site-packages\pluggy\manager.py 92
*** __call__ c:\python\x86\37\lib\site-packages\pluggy\hooks.py 286
*** pytest_runtestloop c:\python\x86\37\lib\site-packages\_pytest\main.py 258
*** _multicall c:\python\x86\37\lib\site-packages\pluggy\callers.py 187
*** <lambda> c:\python\x86\37\lib\site-packages\pluggy\manager.py 86
*** _hookexec c:\python\x86\37\lib\site-packages\pluggy\manager.py 92
*** __call__ c:\python\x86\37\lib\site-packages\pluggy\hooks.py 286
*** _main c:\python\x86\37\lib\site-packages\_pytest\main.py 237
*** wrap_session c:\python\x86\37\lib\site-packages\_pytest\main.py 193
*** pytest_cmdline_main c:\python\x86\37\lib\site-packages\_pytest\main.py 230
*** _multicall c:\python\x86\37\lib\site-packages\pluggy\callers.py 187
*** <lambda> c:\python\x86\37\lib\site-packages\pluggy\manager.py 86
*** _hookexec c:\python\x86\37\lib\site-packages\pluggy\manager.py 92
*** __call__ c:\python\x86\37\lib\site-packages\pluggy\hooks.py 286
*** main c:\python\x86\37\lib\site-packages\_pytest\config\__init__.py 90
*** <module> c:\Python\x86\37\Scripts\pytest.exe\__main__.py 7
  • Kann Python-Piped- oder interaktive Sitzungen verarbeiten.

Nachteile:

  • Eine Art sehr präzise und kann Module zurückgeben, die in einer ausführbaren Datei registriert sind, wie für die, pytest.exedie möglicherweise nicht das sind, was Sie wollen.
  • inspect.getmodule Je nach Anschluss kann bei gültigen Modulen immer noch None zurückgegeben werden

Ich habe eine Erweiterung für Python: Wie importiere ich ein Modul unter Angabe des vollständigen Pfads?

Die Erweiterung mit Wrapper-Funktionen für diesen Fall:

def tkl_get_stack_frame_module_by_offset(skip_stack_frames = 0, use_last_frame_on_out_of_stack = False):
  ...

def tkl_get_stack_frame_module_by_name(name = '<module>'):
  ...

Sie müssen nur die Erweiterung richtig initialisieren:

# portable import to the global space
sys.path.append(<path-to-tacklelib-module-directory>)
import tacklelib as tkl

tkl.tkl_init(tkl, global_config = {'log_import_module':os.environ.get('TACKLELIB_LOG_IMPORT_MODULE')})

# cleanup
del tkl # must be instead of `tkl = None`, otherwise the variable would be still persist
sys.path.pop()

# use `tkl_*` functions directly from here ...
Andry
quelle