Pythonで現在実行中のモジュールまたはクラス名にアクセスするにはどうすればよいですか?

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

  •  03-07-2019
  •  | 
  •  

質問

インポートされたモジュール内から現在実行中のモジュールまたはクラス名を動的に取得できるようにしたいと思います。コードは次のとおりです。

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です)

使用したいのは inspect モジュールで、 Pythonランタイムスタック。このチュートリアルをご覧ください。あなたがしたいことのほぼ正確な例を提供すると思います。

__ 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]
ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top