インポートされたモジュール内から現在実行中のモジュールまたはクラス名を動的に取得できるようにしたいと思います。コードは次のとおりです。
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( __)
これにより、ほぼすべてのログの命名が完全に処理されます。
これは、現在のモジュールを参照するために機能するはずです:
import sys
sys.modules[__name__]
「現在実行中のモジュール」は明らかにfooです。これは現在実行中の関数を含んでいるからです-あなたが望むものについてのより良い説明はfooの即時呼び出し元のモジュール(あなたがf() barの関数によって呼び出されるfooの関数から、どれだけ上に行きたいかは、これが何をしたいかによって異なります。
いずれの場合でも、すぐに呼び出し元が必要だと仮定すると、呼び出しスタックをたどることでこれを取得できます。これは sys._getframe
を呼び出すことで達成できます。適切なレベル数で歩きます。
def f():
caller = sys._getframe(1) # Obtain calling frame
print "Called from module", caller.f_globals['__name__']
[編集]:実際には、上記で提案した inspect モジュールを使用すると、おそらくスタックフレームを取得するよりクリーンな方法になります。同等のコードは次のとおりです。
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__
___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」を実行することを忘れないでください。)
foo
の範囲外なので、それが可能だとは思わない。 fooは無数の他のモジュールやアプリケーションから呼び出される可能性があるため、内部スコープのみを認識します。
Pythonを作成してからしばらく経ちましたが、呼び出し元のグローバルとローカルに traceback でアクセスできると信じています。
ファイルの名前のみが必要な場合:
file_name = __file__.split("/")[len(__file__.split("/"))-1]
フォルダーを含む現在のファイルモジュールを取得するには、次のようにします。
import os
parts = os.path.splitext(__name__)
module_name = parts[len(parts) - 2]