Pythonで現在のモジュールの属性への参照を取得する方法


119

私がやろうとしていることは、コマンドラインでは次のようになります:

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

それ自体mymoduleから定義されているすべての名前への参照を取得するにはどうすればよいmymoduleですか?

このようなもの:

# mymodule.py
names = dir(__thismodule__)

回答:


135

ただglobals()を使用してください

globals()—現在のグローバルシンボルテーブルを表すディクショナリを返します。これは常に現在のモジュールのディクショナリです(関数またはメソッド内では、これはそれが定義されているモジュールであり、呼び出し元のモジュールではありません)。

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


4
定義モジュールの代わりに、呼び出しモジュールのgloabals()にアクセスする方法はありますか?
dimo414 2012

9
トレースバックモジュール(docs.python.org/library/traceback.html)から呼び出し元のグローバルを取得することもできますが、これはダークマジックの領域に入り込んでいます。何をしようとしているのかわかりませんが、必要に応じてデザインを見直してください。
Maciejパステルナッキ

「Xが必要です(Yを実行するには)-> Xは必要ありませんが、Zが必要です」という古典的なケース。私はXが必要です!違反はありません、これは面白いと思います。最も投票された答えが私に必要な答えを与えてくれます:)
pawamoy

globals()は呼び出されたコンテキストに依存するため、誤った結果を返す可能性があることに注意してください。たとえば、クラス関数から呼び出しを行うと、現在のモジュールコンテキストではなく、クラスにリンクされたグローバルコンテキストが返されますが、これは大きく異なります。フリー関数から呼び出しを行った場合でも、関数のインポート方法によっては、異なるモジュールグローバルコンテキストを返す可能性があります。
Andry

163

前述のように、モジュールで定義された名前のリストを提供するdir()とは対照的に、グローバルは辞書を提供します。これが通常行われているのを見る方法は次のとおりです。

import sys
dir(sys.modules[__name__])

2
sys.modulesにリストされていないように見えるので、これは' main 'モジュール(ターミナルで実行されるモジュールが呼び出されるモジュール)では機能しないというコメントを追加しようとしましたが、実際には機能します:)
markm '28 / 07/28

ただし、ipdbからは機能しないようです(「import ipdb; ipdb.set_trace()」をファイルに挿入してください)。
gatoatigrado 2012年

9
優れた!これにより、現在のモジュールのdocstringを使用法メッセージとして使用できます- sys.modules[__name__].__doc__
ジョージ2013

そして、超ハックを取得します。operators.attrgetter('module.attribute')(sys.modules[__name__])-ご存知のように、文字列からパッケージを動的にインポートしたり、クラスなどに属していないときにそれらにサルのパッチを適用したりしないように人々が言うクレイジーなことをした場合...
ケーシー

2
これは現在の名前空間で定義されているため、george:sys.modules[__name__].__doc__==でコメントを読んでいる人は誰でも__doc__。したがって、モジュールオブジェクトをフェッチして独自の属性にアクセスする必要はありません。
Oliver Bestwalter

1

答えが遅いかもしれませんが、自分で正解を見つけることができませんでした。inspect.stack()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

長所

  • メソッドよりも正確globals()
  • スタックの中間フレームには依存しません。たとえば、フックや次のような3dpartyツールを使用して追加できます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
  • Pythonパイプまたはインタラクティブセッションを処理できます。

短所:

  • 一種の非常に正確であり、実行可能ファイルに登録されているモジュールを返すことができpytest.exeます。
  • inspect.getmodule フックによっては、有効なモジュールでまだNoneを返す場合があります

Pythonの拡張機能があります: フルパスを指定してモジュールをインポートするにはどうすればよいですか?

その場合のラッパー関数を持つ拡張機能:

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>'):
  ...

拡張機能を適切に初期化する必要があります:

# 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 ...
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.