Pythonでは、traceback
モジュールを使用せずに、その関数内からその関数の名前を判断する方法はありますか?
関数バー付きのモジュールfooがあるとしましょう。 foo.bar()
を実行するとき、barがbarの名前を知る方法はありますか?もっと良いのは、foo.bar
の名前ですか?
#foo.py
def bar():
print "my name is", __my# <== how do I calculate this at runtime?
Pythonには、関数自体にその関数またはその名前にアクセスするための機能がありません。それは 提案されています が拒否されました。自分でスタックをプレイしたくない場合は、コンテキストに応じて"bar"
またはbar.__name__
を使用してください。
指定された拒否通知は以下のとおりです。
このPEPは拒否されました。それがどのように実装されるべきか、またはEdgeケースで正確なセマンティクスがどうあるべきかは明確ではありません。また、十分な重要なユースケースはありません。反応はせいぜい白熱しています。
import inspect
def foo():
print(inspect.stack()[0][3])
同じ結果を得るにはいくつかの方法があります。
from __future__ import print_function
import sys
import inspect
def what_is_my_name():
print(inspect.stack()[0][0].f_code.co_name)
print(inspect.stack()[0][3])
print(inspect.currentframe().f_code.co_name)
print(sys._getframe().f_code.co_name)
inspect.stack
呼び出しは他のものよりも数千倍遅いことに注意してください。
$ python -m timeit -s 'import inspect, sys' 'inspect.stack()[0][0].f_code.co_name'
1000 loops, best of 3: 499 usec per loop
$ python -m timeit -s 'import inspect, sys' 'inspect.stack()[0][3]'
1000 loops, best of 3: 497 usec per loop
$ python -m timeit -s 'import inspect, sys' 'inspect.currentframe().f_code.co_name'
10000000 loops, best of 3: 0.1 usec per loop
$ python -m timeit -s 'import inspect, sys' 'sys._getframe().f_code.co_name'
10000000 loops, best of 3: 0.135 usec per loop
@Andreas Jungが に示すアプローチを使用して定義された名前を取得できますが、それは関数がで呼び出された名前ではない場合があります。
import inspect
def Foo():
print inspect.stack()[0][3]
Foo2 = Foo
>>> Foo()
Foo
>>> Foo2()
Foo
その区別があなたにとって重要であるかどうか私は言うことができません。
functionNameAsString = sys._getframe().f_code.co_name
私は非常によく似たことを望んでいました。私はコードの多くの場所にあるログ文字列に関数名を入れたかったのです。おそらく最善の方法ではありませんが、現在の関数の名前を取得する方法があります。
この便利なユーティリティを近くに置いておきます。
import inspect
myself = lambda: inspect.stack()[1][3]
使用法:
myself()
これを行うにはinspect
が最善の方法だと思います。例えば:
import inspect
def bar():
print("My name is", inspect.stack()[0][3])
関数名を書くラッパーを見つけました
from functools import wraps
def tmp_wrap(func):
@wraps(func)
def tmp(*args, **kwargs):
print func.__name__
return func(*args, **kwargs)
return tmp
@tmp_wrap
def my_funky_name():
print "STUB"
my_funky_name()
これは印刷されます
my_funky_name
スタブ
print(inspect.stack()[0].function)
も動作するようです(Python 3.5)。
これは実際には質問に対する他の答えから導き出されたものです。
これが私の考えです:
import sys
# for current func name, specify 0 or no argument.
# for name of caller of current func, specify 1.
# for name of caller of caller of current func, specify 2. etc.
currentFuncName = lambda n=0: sys._getframe(n + 1).f_code.co_name
def testFunction():
print "You are in function:", currentFuncName()
print "This function's caller was:", currentFuncName(1)
def invokeTest():
testFunction()
invokeTest()
# end of file
Inspect.stack()を使用するよりもこのバージョンの利点は、数千倍速いはずです[Alex Melihoffによる投稿とsys._getframe()の使用とinspect.stack()の使用に関するタイミングを参照)。
import inspect
def whoami():
return inspect.stack()[1][3]
def whosdaddy():
return inspect.stack()[2][3]
def foo():
print "hello, I'm %s, daddy is %s" % (whoami(), whosdaddy())
bar()
def bar():
print "hello, I'm %s, daddy is %s" % (whoami(), whosdaddy())
foo()
bar()
IDEにコード出力
こんにちは、私はフーです、パパは
こんにちは、私はバーです、パパはfooです
こんにちは、私はバーです、パパはです
import sys
def func_name():
"""
:return: name of caller
"""
return sys._getframe(1).f_code.co_name
class A(object):
def __init__(self):
pass
def test_class_func_name(self):
print(func_name())
def test_func_name():
print(func_name())
テスト:
a = A()
a.test_class_func_name()
test_func_name()
出力:
test_class_func_name
test_func_name
これは未来を見据えたアプローチです。
@ CamHartと@ Yuvalの提案を@ RoshOxymoronの 承認済みの回答 と組み合わせると、回避することができます。
_hidden
および廃止予定の可能性があるメソッドだから私はこれが将来のPythonのバージョン(2.7.3と3.3.2でテストされている)で素晴らしいと思うと思います:
from __future__ import print_function
import inspect
def bar():
print("my name is '{}'".format(inspect.currentframe().f_code.co_name))
あなたはデコレータを使うことができます:
def my_function(name=None):
return name
def get_function_name(function):
return function(name=function.__name__)
>>> get_function_name(my_function)
'my_function'
私はCamHartが言ったことをしました:
import sys
def myFunctionsHere():
print(sys._getframe().f_code.co_name)
myFunctionsHere()
出力:
C:\ Python\Python36\python.exe C:/Python/GetFunctionsNames/TestFunctionsNames.py myFunctionsHere
プロセスは終了コード0で終了しました
これを使用してください(#Ron Davisの回答に基づく)。
import sys
def thisFunctionName():
"""Returns a string with the name of the function it's called from"""
return sys._getframe(1).f_code.co_name
なぜ人々がそれを複雑にするのか分かりません:
import sys
print("%s/%s" %(sys._getframe().f_code.co_filename, sys._getframe().f_code.co_name))
私は最近、関数のコンテキストから関数のdocstringにアクセスするために上記の答えを使用しようとしましたが、上記の質問は名前文字列を返すだけだったのでうまくいきませんでした。
幸い、私は簡単な解決策を見つけました。私のように、あなたは単にあなたがeval()を関数名の文字列に適用することができる名前を表す文字列を得るよりむしろ関数を参照したいです。
import sys
def foo():
"""foo docstring"""
print(eval(sys._getframe().f_code.co_name).__doc__)
私は多重継承のシナリオの中で安全にsuperを呼ぶために使われる私自身のアプローチをします(私はすべてのコードを置きます)
def safe_super(_class, _inst):
"""safe super call"""
try:
return getattr(super(_class, _inst), _inst.__fname__)
except:
return (lambda *x,**kx: None)
def with_name(function):
def wrap(self, *args, **kwargs):
self.__f= function.__name__
return function(self, *args, **kwargs)
return wrap
使用例
class A(object):
def __init__():
super(A, self).__init__()
@with_name
def test(self):
print 'called from A\n'
safe_super(A, self)()
class B(object):
def __init__():
super(B, self).__init__()
@with_name
def test(self):
print 'called from B\n'
safe_super(B, self)()
class C(A, B):
def __init__():
super(C, self).__init__()
@with_name
def test(self):
print 'called from C\n'
safe_super(C, self)()
それをテストする:
a = C()
a.test()
出力:
called from C
called from A
called from B
各@with_name装飾メソッド内では、現在の関数名としてself .__ fname__にアクセスできます。
スタック要素に頼らないことをお勧めします。誰かがあなたのコードを異なるコンテキスト(例えばpythonインタプリタ)の中で使用すると、あなたのスタックは変更されてあなたのインデックスを壊すでしょう([0] [3])。
私はあなたにそのような何かを提案する:
class MyClass:
def __init__(self):
self.function_name = None
def _Handler(self, **kwargs):
print('Calling function {} with parameters {}'.format(self.function_name, kwargs))
self.function_name = None
def __getattr__(self, attr):
self.function_name = attr
return self._Handler
mc = MyClass()
mc.test(FirstParam='my', SecondParam='test')
mc.foobar(OtherParam='foobar')