回答:
Pythonには、関数自体内で関数またはその名前にアクセスする機能がありません。提案されましたが却下されました。自分でスタックを操作したくない場合は、コンテキストを使用する"bar"
か、bar.__name__
依存する必要があります。
指定された拒否通知は次のとおりです。
このPEPは拒否されました。それがどのように実装されるべきか、または正確なセマンティクスがエッジケースでどのようにあるべきかは明確ではなく、与えられた十分な重要なユースケースがありません。応答はせいぜいぬるいです。
inspect.currentframe()
そのような方法の1つです。
print(inspect.currentframe().f_code.co_name)
import inspect
def foo():
print(inspect.stack()[0][3])
print(inspect.stack()[1][3]) #will give the caller of foos name, if something called foo
[1][3]
発信者の名前を取得することもできるので、これは素晴らしいことです。
print(inspect.currentframe().f_code.co_name)
または、発信者の名前を取得するために使用することもできます:print(inspect.currentframe().f_back.f_code.co_name)
。すべてのスタックフレームのリストを取得するのではないので、より高速になるはずですinspect.stack()
。
inspect.currentframe().f_back.f_code.co_name
装飾されたメソッドでは動作しませんが、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
inspect.currentframe()
実行時間とプライベートメンバーの使用の間の適切なトレードオフのようです
0.100 usec
や0.199 usec
けどいずれかの方法-高速化オプション1および2よりも数百倍、オプション4と同等(アントニーHatchkinsは3三倍速くオプション4以上のオプションを見つけましたが)。
sys._getframe().f_code.co_name
over を使用しinspect.currentframe().f_code.co_name
ていsys
ます。それは合理的な決定ですか?(速度がかなり似ているように見える)
@Andreas Jungが示すアプローチを使用して定義された名前を取得できますが、関数が呼び出された名前ではない場合があります。
import inspect
def Foo():
print inspect.stack()[0][3]
Foo2 = Foo
>>> Foo()
Foo
>>> Foo2()
Foo
その区別があなたにとって重要であるかどうかは私には言えません。
.func_name
。Pythonのクラス名と関数名は1つであり、それらを参照する変数は別のものであることを覚えておく価値があります。
Foo2()
印刷したいかもしれませんFoo
。次に例を示しますFoo2 = function_dict['Foo']; Foo2()
。この場合、Foo2はおそらくコマンドラインパーサーの関数ポインターです。
functionNameAsString = sys._getframe().f_code.co_name
コード内のさまざまな場所にあるログ文字列に関数名を入れたかったので、非常によく似たものが必要でした。おそらくそれを行うための最良の方法ではありませんが、現在の関数の名前を取得する方法は次のとおりです。
f
フレームとco
コードを念頭に置いてください。私はそれをあまり使用しないので、それをいくつかのスニペットに保存するだけでよいです:-)
私はこの便利なユーティリティを近くに置きます:
import inspect
myself = lambda: inspect.stack()[1][3]
使用法:
myself()
関数名を書き込むラッパーを見つけました
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
スタブ
my_funky_name.__name__
です。func .__ name__を新しいパラメーターとして関数に渡すことができます。func(* args、** kwargs、my_name = func .__ name__)。関数内からデコレータ名を取得するには、inspectを使用する必要があると思います。しかし、実行中の関数内で自分の関数を制御する関数の名前を取得しています...それは、美しいミームの始まりのように聞こえます:)
これは実際には、質問に対する他の回答から導き出されます。
これが私の見解です。
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()を使用するよりもこのバージョンの利点は、数千倍高速になることです[sys._getframe()の使用とinspect.stack()の使用に関するAlex Melihoffの投稿とタイミングを参照]。
これが将来を見据えたアプローチです。
@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))
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
なぜ人々はそれを複雑にするのか分かりません:
import sys
print("%s/%s" %(sys._getframe().f_code.co_filename, sys._getframe().f_code.co_name))
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では、コード出力
こんにちは、私はフーです、パパは
こんにちは、私はバーです、パパはフーです
こんにちは、私はバーです、パパは
デコレータを使用できます。
def my_function(name=None):
return name
def get_function_name(function):
return function(name=function.__name__)
>>> get_function_name(my_function)
'my_function'
__name__
は、関数の属性に到達するための複雑な方法のように見えます。使用法は、取得しようとしているものを知ることを必要とします。これは、関数がその場で定義されていない単純なケースでは、私にはあまり役に立ちません。
多重継承シナリオ内で安全にスーパーを呼び出すために使用する独自のアプローチを実行します(すべてのコードを配置します)
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.__fname__ = 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')
これは、デコレータを使用して簡単に実行できます。
>>> from functools import wraps
>>> def named(func):
... @wraps(func)
... def _(*args, **kwargs):
... return func(func.__name__, *args, **kwargs)
... return _
...
>>> @named
... def my_func(name, something_else):
... return name, something_else
...
>>> my_func('hello, world')
('my_func', 'hello, world')
traceback
です。答えやコメントの時代でさえそれを裏付けるようには見えません。