web-dev-qa-db-ja.com

その関数内から(トレースバックを使用せずに)関数名を決定します。

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?
375
Rob

Pythonには、関数自体にその関数またはその名前にアクセスするための機能がありません。それは 提案されています が拒否されました。自分でスタックをプレイしたくない場合は、コンテキストに応じて"bar"またはbar.__name__を使用してください。

指定された拒否通知は以下のとおりです。

このPEPは拒否されました。それがどのように実装されるべきか、またはEdgeケースで正確なセマンティクスがどうあるべきかは明確ではありません。また、十分な重要なユースケースはありません。反応はせいぜい白熱しています。

155
Rosh Oxymoron
import inspect

def foo():
   print(inspect.stack()[0][3])
342
Andreas Jung

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

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
124
Alex Granovsky

@Andreas Jungが に示すアプローチを使用して定義された名前を取得できますが、それは関数がで呼び出された名前ではない場合があります。

import inspect

def Foo():
   print inspect.stack()[0][3]

Foo2 = Foo

>>> Foo()
Foo

>>> Foo2()
Foo

その区別があなたにとって重要であるかどうか私は言うことができません。

43
bgporter
functionNameAsString = sys._getframe().f_code.co_name

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

34
Ron Davis

この便利なユーティリティを近くに置いておきます。

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

使用法:

myself()
20
xxyzzy

これを行うにはinspectが最善の方法だと思います。例えば:

import inspect
def bar():
    print("My name is", inspect.stack()[0][3])
18
Bjorn

関数名を書くラッパーを見つけました

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

スタブ

14
cad106uk

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

11
Pierre Voisin

これは実際には質問に対する他の答えから導き出されたものです。

これが私の考えです:

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()の使用に関するタイミングを参照)。

11
Gino
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です

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

10
Lee
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
9
nordborn

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

@ CamHartと@ Yuvalの提案を@ RoshOxymoronの 承認済みの回答 と組み合わせると、回避することができます。

  • _hiddenおよび廃止予定の可能性があるメソッド
  • スタックへのインデックス(将来のpythonsで並べ替えられる可能性があります)

だから私はこれが将来の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))
9
hobs

あなたはデコレータを使うことができます:

def my_function(name=None):
    return name

def get_function_name(function):
    return function(name=function.__name__)

>>> get_function_name(my_function)
'my_function'
7

私は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
3
nerdfever.com

なぜ人々がそれを複雑にするのか分かりません:

import sys 
print("%s/%s" %(sys._getframe().f_code.co_filename, sys._getframe().f_code.co_name))
3
karthik r

私は最近、関数のコンテキストから関数のdocstringにアクセスするために上記の答えを使用しようとしましたが、上記の質問は名前文字列を返すだけだったのでうまくいきませんでした。

幸い、私は簡単な解決策を見つけました。私のように、あなたは単にあなたがeval()を関数名の文字列に適用することができる名前を表す文字列を得るよりむしろ関数を参照したいです。

import sys
def foo():
    """foo docstring"""
    print(eval(sys._getframe().f_code.co_name).__doc__)
3
John Forbes

私は多重継承のシナリオの中で安全に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__にアクセスできます。

3

スタック要素に頼らないことをお勧めします。誰かがあなたのコードを異なるコンテキスト(例えば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')
2
Genschi