Pythonで現在実行中のモジュールまたはクラス名にアクセスするにはどうすればよいですか?
質問
インポートされたモジュール内から現在実行中のモジュールまたはクラス名を動的に取得できるようにしたいと思います。コードは次のとおりです。
foo.py:
def f():
print __name__
bar.py:
from foo import f
def b(): f()
__ name __
は関数を含むモジュールの名前であるため、これは明らかに機能しません。 foo
モジュール内でアクセスしたいのは、 foo
を使用している現在実行中のモジュールの名前です。したがって、上記の場合は bar
になりますが、他のモジュールが foo
をインポートした場合、 foo
がその名前に動的にアクセスできるようにしますモジュール。
編集: inspect
モジュールは非常に有望に見えますが、まさに私が探していたものではありません。私が望んでいたのは、現在実行中のモジュールの名前を含むアクセス可能なグローバルまたは環境レベルの変数のようなものでした。その情報を見つけるためにスタックを走査するのは嫌だというわけではありません-Pythonが既にそのデータを公開しているかもしれないと思ったのです。
編集:これを使用する方法を次に示します。エラーをファイルに記録する必要がある2つの異なるDjangoアプリケーションがあります。 「AppOne」と呼ばれているとしましょう。および「AppTwo」。また、これらのファイルをログに記録する場所もあります:" / home / hare / app_logs
"。任意の時点で各アプリケーションで、ロガーモジュールをインポートし、ログ文字列をファイルに書き込むログ関数を呼び出すことができるようにしたいと思います。しかし、私がやりたいのは、現在のアプリケーションの名前(" AppOne"または" AppTwo")である app_logs
の下にディレクトリを作成し、各アプリケーションのログファイルがそれぞれのログディレクトリ。
これを行うには、ロガーモジュールが現在のアプリケーションの名前を示す何らかのグローバル変数にアクセスして、親ロギングディレクトリの場所を認識して作成する責任があるため、最善の方法だと思いましたまだ存在しない場合、アプリケーションのログディレクトリ。
解決
質問からではなく、コメントから。
自分がやろうとしていることが可能かどうかを知りたいだけです。
「可能ですか」に対する答え常に「はい」です。常に。あなたの質問がタイムトラベル、反重力、または永久運動に関係しない限り。
答えは常に「はい」なので、質問の形式は正しくありません。本当の質問は、「ロギングモジュールにクライアントの名前を知らせる良い方法は何ですか?」です。またはそのようなもの。
答えは「パラメータとして受け入れる」です。ミステリアスなグローバルやその他のトリックを調べたり探したりすることをいじらないでください。
logging.getLogger()の設計パターンに従い、明示的に名前が付けられたロガーを使用します。一般的なイディオムは次のとおりです
logger= logging.getLogger( __name__ )
これは、ほぼすべてのログ命名を完全に処理します。
他のヒント
これは現在のモジュールを参照するために動作するはずです:
import sys
sys.modules[__name__]
"現在実行中のモジュール"それが現在実行中の関数を含んでいるので、明らかにfooです-あなたが望むものについてのより良い説明は、fooの即時呼び出し元のモジュールであると思います(呼び出されたfooの関数からaf()を呼び出している場合、それ自体はfooかもしれません)バーの機能によって。あなたがどれだけ上に行きたいかは、あなたがこれに何を望むかに依存します。
いずれの場合でも、すぐに呼び出し元が必要だと仮定すると、コールスタックをたどってこれを取得できます。これは、 sys._getframe
、歩くのに適切なレベル数で。
def f():
caller = sys._getframe(1) # Obtain calling frame
print "Called from module", caller.f_globals['__name__']
[編集] :実際には、検査を使用して上記で提案したモジュールは、おそらくスタックフレームを取得するよりクリーンな方法です。同等のコードは次のとおりです。
def f():
caller = inspect.currentframe().f_back
print "Called from module", caller.f_globals['__name__']
(sys._getframeは内部使用のために文書化されています-検査モジュールはより信頼性の高いAPIです)
__ file __
は、呼び出しが行われている現在のモジュールのパスです。
" __ main __"への参照を取得するには別の場合のモジュール:
import sys
sys.modules['__main__']
その後、モジュールのファイルパスを取得するには、名前を含めます:
sys.modules['__main__'].__file__
" __ main __"内の場合モジュール、単に使用: __ file __
ファイルパスからファイル名のみを取得するには:
import os
os.path.basename(file_path)
ファイル名と拡張子を区別するには:
file_name.split(".")[0]
クラスインスタンスの名前を取得するには:
instance.__class__.__name__
クラスの名前を取得するには:
class.__name__
foo
の範囲外であるため、それが可能だとは思わない。 fooは、他の無数のモジュールやアプリケーションから呼び出される可能性があるため、内部スコープのみを認識します。
__ file __
を単独で使用すると、メインモジュールの相対パスとインポートされたモジュールの絶対パスが提供されます。これに気づくと、 os.path
ツールの少しの助けを借りて、常にどちらの方法でもモジュールファイルを取得できます。
ファイル名には __ file __。split(os.path.sep)[-1]
のみを使用します。
完全なパスを使用するには、 os.path.abspath(__ file __)
を使用します。
デモ:
/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
結果:
## 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'}
「。py」を末尾から削除する場合は、簡単に実行できます。 (ただし、代わりに '.pyc'を実行することを忘れないでください。)
Pythonを実行してからしばらく経ちましたが、そのトレースバック。
ファイルの名前のみが必要な場合:
file_name = __file__.split("/")[len(__file__.split("/"))-1]
フォルダを含む現在のファイルモジュールを取得するには、次のようにします。
import os
parts = os.path.splitext(__name__)
module_name = parts[len(parts) - 2]