Pythonで関数を呼び出すモジュールの__name__を取得する


96

次をmyapp/foo.py含むとします:

def info(msg):
    caller_name = ????
    print '[%s] %s' % (caller_name, msg)

そしてmyapp/bar.pyが含まれています:

import foo
foo.info('Hello') # => [myapp.bar] Hello

この場合、呼び出し元のモジュール( 'myapp.foo')caller_name__name__属性に設定したいと思います。これはどのように行うことができますか?


他のいくつかのエントリポイントスクリプト呼び出すがbar.pyと仮定..ので、caller_nameすることはできません__main__
シュリダールRatnakumar

回答:


122

検査モジュールをチェックしてください:

inspect.stack() スタック情報を返します。

関数内で、inspect.stack()[1]呼び出し元のスタックを返します。そこから、呼び出し元の関数名、モジュールなどに関する詳細情報を取得できます。

詳細についてはドキュメントを参照してください:

http://docs.python.org/library/inspect.html

また、Doug Hellmannは、彼のPyMOTWシリーズのinspectモジュールのすばらしい記事を持っています:

http://pymotw.com/2/inspect/index.html#module-inspect

編集:あなたが望むことをするいくつかのコードがあります、私は思います:

def info(msg):
    frm = inspect.stack()[1]
    mod = inspect.getmodule(frm[0])
    print '[%s] %s' % (mod.__name__, msg)

1
では__name__、モジュールを使用してこのモジュールの属性をどのように取得しますinspectか?たとえば、上記の例でmyapp.foo(でなくmyapp/foo.py)戻る方法を教えてください。SOに投稿する前に、すでにinspectモジュールを使用してみました。
Sridhar Ratnakumar、2009

6
これはインポートフックと奇妙に相互作用し、ironpythonでは機能せず、jythonで意外な方法で動作する可能性があることに注意してください。このような魔法を避けることができれば最高です。
グリフ

2
また、スタックフレームへの参照を維持すると、PythonのGCが正しく動作しなくなる可能性があることにも注意してください。ここで警告を参照してください:docs.python.org/library/inspect.html#the-interpreter-stack
Kamil Kisiel

6
呼び出し元の関数が修飾(@ ...)されている場合はinspect.stack()[2]、実際の呼び出し元にアクセスする必要があることに注意してください。
Amir Ali Akbari

また、pyinstallerを使用してpythonコードをexeにコンパイルすると、このロジックが正しく機能しないことに注意してください。
2014年

19

同様の問題に直面して、sysモジュールのsys._current_frames()には、少なくとも特定のユースケースで、インスペクションをインポートする必要なしに役立つ興味深い情報が含まれていることがわかりました。

>>> sys._current_frames()
{4052: <frame object at 0x03200C98>}

次に、f_backを使用して「上に移動」できます。

>>> f = sys._current_frames().values()[0]
>>> # for python3: f = list(sys._current_frames().values())[0]

>>> print f.f_back.f_globals['__file__']
'/base/data/home/apps/apricot/1.6456165165151/caller.py'

>>> print f.f_back.f_globals['__name__']
'__main__'

ファイル名には、上記のMark Roddyが提案したように、f.f_back.f_code.co_filenameを使用することもできます。この方法の制限と注意点はわかりません(複数のスレッドが問題になる可能性が高いです)が、私の場合は使用するつもりです。


2
注:pyinstallerを使用してexeにコンパイルした後、inspect.stackコードは失敗しますが、sys._current_frames WORKS FINE ...を使用しているので、これは私にとって推奨される手法です。
2014年

7
前のフレームを取得する方が、sys._getframe(1)を呼び出すよりも簡単ですsys._current_frames()(btwはすべてのスレッドのフレームマッピングを返します)。
hooblei 2015年

hoobleiに感謝します。まだテストしていませんが、マルチスレッド環境では非常に便利です。
Louis LC

inspect.currentframe()代わりに使用することを好みますsys._current_frames().values()[0]
Aran-Fey

3

これはお勧めしませんが、次の方法で目標を達成できます。

def caller_name():
    frame=inspect.currentframe()
    frame=frame.f_back.f_back
    code=frame.f_code
    return code.co_filename

次に、既存のメソッドを次のように更新します。

def info(msg):
    caller = caller_name()
    print '[%s] %s' % (caller, msg)

7
ファイル名は同じではありません__name__
Sridhar Ratnakumar '08 / 07/03
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.