从该函数中确定函数名称(不使用回溯)

Python中,不使用traceback模块,是否可以从该函数中确定函数名称?

说我有一个带功能栏的模块foo。 当执行foo.bar() ,bar是否有办法知道bar的名称? 或者更好的是foo.bar的名称?

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

#1楼

functionNameAsString = sys._getframe().f_code.co_name

我想要一个非常类似的东西,因为我想将函数名称放在一个日志字符串中,该字符串在我的代码中占据了很多位置。 可能不是这样做的最佳方法,但是这是一种获取当前函数名称的方法。


#2楼

有几种方法可以得到相同的结果:

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

#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

存根


#4楼

我将这个方便的实用程序放在附近:

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

用法:

myself()

#5楼

这是一种面向未来的方法。

将@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))

#6楼

您可以使用装饰器:

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楼

这实际上是从问题的其他答案中得出的。

这是我的看法:

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()的时序]。


#8楼

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,爸爸是

你好,我是酒吧,爸爸是foo

你好,我在酒吧,爸爸是


#9楼

我使用自己的方法在多重继承场景中安全地调用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.__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__作为当前函数名称。


#10楼

print(inspect.stack()[0].function)似乎也可以工作(Python 3.5)。


#11楼

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

#12楼

我做了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


#13楼

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

#14楼

Python没有功能来访问函数或函数本身中的名称。 已经提出但遭到拒绝。 如果您不想自己玩堆栈,则应根据上下文使用"bar"bar.__name__

给定的拒绝通知是:

该PEP被拒绝。 尚不清楚在极端情况下应如何实现它或精确的语义,并且给出的重要用例还不够多。 回应充其量是冷淡的。


#15楼

我想inspect是最好的方法。 例如:

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

#16楼

您可以使用@Andreas Jung显示的方法来获得定义的名称,但这可能不是使用该函数调用的名称:

import inspect

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

Foo2 = Foo

>>> Foo()
Foo

>>> Foo2()
Foo

我不能说这种区别对您是否重要。


#17楼

使用此方法(基于#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

#18楼

我最近尝试使用以上答案从该函数的上下文访问该函数的文档字符串,但是由于上述问题仅返回了名称字符串,因此它不起作用。

幸运的是,我找到了一个简单的解决方案。 如果像我一样,您想引用该函数,而不是简单地获取表示名称的字符串,您可以将eval()应用于函数名称的字符串。

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

#19楼

我建议不要依赖堆栈元素。 如果有人在不同的上下文(例如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')

#20楼

我不确定为什么人们会变得复杂:

import sys 
print("%s/%s" %(sys._getframe().f_code.co_filename, sys._getframe().f_code.co_name))
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值