628

Pythonでは、tracebackモジュールを使用せずに、その関数内から関数の名前を決定する方法はありますか?

foofunctionを持つモジュールがあるとしますbar。を実行するとき、の名前を知るfoo.bar()方法はありますか? またはさらに良いのは、の名前ですか?barbarfoo.bar

#foo.py  
def bar():
    print "my name is", __myname__ # <== how do I calculate this at runtime?
4

23 に答える 23

504
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

foo()

出力:

foo
<module_caller_of_foo>
于 2011-02-21T15:16:04.770 に答える
261

Python には、関数または関数内のその名前にアクセスする機能がありません。提案されましたが却下されました。自分でスタックを操作したくない場合は、コンテキストに応じて"bar"orを使用する必要があります。bar.__name__

与えられた拒否通知は次のとおりです。

この PEP は拒否されます。どのように実装する必要があるか、またはエッジケースで正確なセマンティクスがどうあるべきかは明確ではなく、与えられた重要なユースケースが十分ではありません. 反応はせいぜい生ぬるいものでした。

于 2011-02-21T15:16:44.527 に答える
220

同じ結果を得るにはいくつかの方法があります。

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

更新 08/2021 (元の投稿は Python2.7 用に書かれました)

Python 3.9.1 (default, Dec 11 2020, 14:32:07)
[GCC 7.3.0] :: Anaconda, Inc. on linux

python -m timeit -s 'import inspect, sys' 'inspect.stack()[0][0].f_code.co_name'
500 loops, best of 5: 390 usec per loop
python -m timeit -s 'import inspect, sys' 'inspect.stack()[0][3]'
500 loops, best of 5: 398 usec per loop
python -m timeit -s 'import inspect, sys' 'inspect.currentframe().f_code.co_name'
2000000 loops, best of 5: 176 nsec per loop
python -m timeit -s 'import inspect, sys' 'sys._getframe().f_code.co_name'
5000000 loops, best of 5: 62.8 nsec per loop
于 2013-06-28T14:04:54.643 に答える
55
functionNameAsString = sys._getframe().f_code.co_name

コードの多くの場所にあるログ文字列に関数名を入れたかったので、非常によく似たものが欲しかったのです。おそらくこれは最善の方法ではありませんが、現在の関数の名前を取得する方法を次に示します。

于 2013-03-31T03:05:31.227 に答える
31

私はこの便利なユーティリティを近くに置いています:

import inspect
myself = lambda: inspect.stack()[1][3]

使用法:

myself()
于 2014-07-08T09:48:23.860 に答える
29

inspectこれを行うための最良の方法だと思います。例えば:

import inspect
def bar():
    print("My name is", inspect.stack()[0][3])
于 2011-02-21T15:21:01.260 に答える
25

関数名を書き込むラッパーを見つけました

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

スタブ

于 2013-11-25T11:46:55.140 に答える
23

これは実際には、質問に対する他の回答から派生しています。

これが私の見解です:

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 の投稿とタイミングを参照してください]。

于 2015-07-24T16:35:54.857 に答える
18

print(inspect.stack()[0].function)も動作するようです (Python 3.5)。

于 2016-01-07T21:31:14.540 に答える
17

これが将来を見据えたアプローチです。

@CamHart と @Yuval の提案を @RoshOxymoron の受け入れられた回答と組み合わせると、回避できるという利点があります。

  • _hidden廃止される可能性のあるメソッド
  • スタックへのインデックス作成(将来のpythonで並べ替えられる可能性があります)

したがって、これは将来の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))

更新: 3.7.10、3.8.10、および 3.9.5 でテスト済み

于 2015-03-17T21:56:36.337 に答える
14
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 では、コードが出力されます

こんにちは、私はフーです、パパは

こんにちは、バーです、パパはフーです

こんにちは、私はバーです、パパは

于 2015-10-15T22:46:41.207 に答える
13
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
于 2016-10-22T09:37:35.583 に答える
2

Python 3.9sys._getframe().f_back.f_code.co_nameではまったく機能しないため、今後は次のように使用できます。

from inspect import currentframe


def testNameFunction() -> str:
    return currentframe().f_back.f_code.co_name


print(f'function name is {testNameFunction()}(...)')

結果:

function name is testNameFunction(...)
于 2021-08-13T12:25:41.880 に答える