如何以字符串形式获取函数名称?

How to get a function name as a string?

提问人:X10 提问时间:10/31/2008 最后编辑:Mateen UlhaqX10 更新时间:4/17/2022 访问量:831066

问:

如何以字符串形式获取函数的名称?

def foo():
    pass

>>> name_of(foo)
"foo"
Python 字符串 函数

评论

0赞 Intrastellar Explorer 7/22/2023
getattr(func, "__name__", str(func))是我使用的,以防万一它是一个没有属性的(或其他对象)Mock__name__

答:

47赞 Markus Jarderot 10/31/2008 #1
my_function.func_name

函数还有其他有趣的属性。键入以列出它们。 是编译函数,存储为字符串。dir(func_name)func_name.func_code.co_code

import dis
dis.dis(my_function)

将以几乎人类可读的格式显示代码。:)

评论

5赞 Federico A. Ramponi 10/31/2008
f.__name__ 和 f.func_name 有什么区别?
16赞 Matthew Trevor 10/31/2008
Sam:名字是私人的,__names很特别,在概念上是有区别的。
14赞 gwideman 2/21/2014
如果有人对 Matthew 的前面答案感到困惑,评论系统会将一些双下划线解释为粗体代码。用反引号转义,消息应为:是私人的,是特殊的。__names____names
17赞 MestreLion 8/23/2014
实际上,我认为正确的是私有的(前面的单下划线,只是一个约定),是特殊的(前后双下划线)。不确定之前的双下划线是否有任何意义,正式或作为惯例。_names__names__
20赞 Daenyth 4/7/2017
func_name在 python3 中不再存在,因此如果您想要兼容性,则需要使用func.__name__
1357赞 user28409 11/1/2008 #2
my_function.__name__

使用是首选方法,因为它应用一致。与 不同,它也适用于内置函数:__name__func_name

>>> import time
>>> time.time.func_name
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
AttributeError: 'builtin_function_or_method' object has no attribute 'func_name'
>>> time.time.__name__ 
'time'

此外,双下划线向读者表明这是一个特殊属性。作为奖励,类和模块也有一个属性,所以你只需要记住一个特殊的名字。__name__

评论

446赞 mbargiel 7/26/2013
因为在某些情况下,您会得到一些函数对象作为函数的参数,并且您需要显示/存储/操作该函数的名称。也许您正在生成文档、帮助文本、操作历史记录等。所以不,你并不总是对函数名称进行硬编码。
2赞 Richard Gomes 8/31/2013
@mgargiel:我想说的是:假设你有一个定义了 100 个方法的类,其中所有方法都只是包装器,它调用一个私有方法,传递包装器本身的名称。像这样的东西:.您还有另一个选择,那就是:。所以,Albert Vonpupp 的答案在我看来更好。def wrapper(kwargs): super(ExtendedClass,self).call('wrapper', kwargs)def wrapper(kwargs): super(ExtendedClass,self).call(sys._getframe().f_code.co_name, kwargs)
19赞 Russell Borogove 8/31/2013
@RichardGomes 一个答案适用于在函数本身中获取名称,另一个答案适用于从函数引用中获取名称。OP所写的问题表明了后者。
27赞 ali-hussain 9/19/2013
@RichardGomes 实际上,我来问这个问题是为了寻找解决这个问题的方法。我试图解决的问题是创建一个可用于记录我所有调用的装饰器。
24赞 wim 3/14/2014
@RichardGomes函数是第一类对象,那么绑定到它们的函数可以不止名称。不一定是这样。f.__name__ == 'f'
410赞 Albert Vonpupp 11/22/2012 #3

若要从内部获取当前函数或方法的名称,请考虑:

import inspect

this_function_name = inspect.currentframe().f_code.co_name

sys._getframe也有效,而不是,尽管后者避免访问私有函数。inspect.currentframe

若要改为获取调用函数的名称,请考虑 中所示。f_backinspect.currentframe().f_back.f_code.co_name


如果还使用 ,则可以抱怨:mypy

错误:“Optional[FrameType]”的项“None”没有属性“f_code”

要抑制上述错误,请考虑:

import inspect
import types
from typing import cast

this_function_name = cast(types.FrameType, inspect.currentframe()).f_code.co_name

评论

63赞 Richard Gomes 7/12/2013
+1:这是我想看到的答案。其他答案假设调用方已经知道函数名称,这在这个问题的上下文中是无稽之谈。
126赞 mbargiel 7/26/2013
理查德:不,没有。你假设你直接在函数定义的同一范围内调用名称或func_name,但通常情况并非如此。请记住,函数是对象 - 它们可以作为参数传递给其他函数,存储在列表/字典中以供以后查找或执行等。
13赞 senderle 1/31/2016
@paulus_almighty,深入研究堆栈框架并不让我感到抽象!事实上,它与抽象相反。请参阅文档中的实现详细说明。并非所有的 Python 实现都包含 -- 它直接连接到 CPython 的内部。sys._getframe
8赞 user2357112 3/29/2016
这仅适用于函数内部,但问题指定不应调用该函数。
7赞 m3nda 1/4/2017
如果你想把你的函数包装成更有用和更容易记住的东西,你必须检索第 1 帧,比如 ,这样你就可以定义一个函数,并期望得到调用的函数的所需名称。sys._getframe(1).f_code.co_nameget_func_name()
19赞 sandyc 8/31/2013 #4

sys._getframe()不能保证在Python的所有实现中都可用(参见参考文献),您可以使用该模块来做同样的事情,例如。traceback

import traceback
def who_am_i():
   stack = traceback.extract_stack()
   filename, codeline, funcName, text = stack[-2]

   return funcName

调用 将返回当前进程详细信息。stack[-1]

评论

0赞 SingleNegationElimination 8/31/2013
对不起,如果未定义,则也无法操作。后者提供了前者功能的粗略超集;你不能指望看到一个而没有另一个。事实上,在 IronPython 2.7 中总是返回 .-1sys._getframe()traceback.extract_stackextract_stack()[]
39赞 Demyn 12/21/2013 #5

此函数将返回调用方的函数名称。

def func_name():
    import traceback
    return traceback.extract_stack(None, 2)[0][2]

这就像 Albert Vonpupp 的回答带有友好的包装纸。

评论

2赞 emmagras 10/18/2014
我在索引 [2] 中有“<module>”,但以下内容有效:traceback.extract_stack(None, 2)[0][-1]
4赞 mike01010 11/22/2014
对我来说,这不起作用,但这确实有效:traceback.extract_stack()[-1][2]
0赞 Jcc.Sanabria 12/20/2018
如果将第一个索引更改为 1,这有效,你们应该在评论之前学会调试......traceback.extract_stack(无,2)[1][2]
21赞 Jim G. 3/26/2016 #6

作为 @Demyn 答案的扩展,我创建了一些实用函数,用于打印当前函数的名称和当前函数的参数:

import inspect
import logging
import traceback

def get_function_name():
    return traceback.extract_stack(None, 2)[0][2]

def get_function_parameters_and_values():
    frame = inspect.currentframe().f_back
    args, _, _, values = inspect.getargvalues(frame)
    return ([(i, values[i]) for i in args])

def my_func(a, b, c=None):
    logging.info('Running ' + get_function_name() + '(' + str(get_function_parameters_and_values()) +')')
    pass

logger = logging.getLogger()
handler = logging.StreamHandler()
formatter = logging.Formatter(
    '%(asctime)s [%(levelname)s] -> %(message)s')
handler.setFormatter(formatter)
logger.addHandler(handler)
logger.setLevel(logging.INFO)

my_func(1, 3) # 2016-03-25 17:16:06,927 [INFO] -> Running my_func([('a', 1), ('b', 3), ('c', None)])
29赞 radato 7/19/2016 #7

我喜欢使用函数装饰器。 我添加了一个类,它也对函数时间进行了乘以。假设 gLog 是一个标准的 python 记录器:

class EnterExitLog():
    def __init__(self, funcName):
        self.funcName = funcName

    def __enter__(self):
        gLog.debug('Started: %s' % self.funcName)
        self.init_time = datetime.datetime.now()
        return self

    def __exit__(self, type, value, tb):
        gLog.debug('Finished: %s in: %s seconds' % (self.funcName, datetime.datetime.now() - self.init_time))

def func_timer_decorator(func):
    def func_wrapper(*args, **kwargs):
        with EnterExitLog(func.__name__):
            return func(*args, **kwargs)

    return func_wrapper

所以现在你所要做的就是装饰它,瞧

@func_timer_decorator
def my_func():
52赞 lapis 11/7/2017 #8

如果您也对类方法感兴趣,Python 3.3+ 除了 .__qualname____name__

def my_function():
    pass

class MyClass(object):
    def method(self):
        pass

print(my_function.__name__)         # gives "my_function"
print(MyClass.method.__name__)      # gives "method"

print(my_function.__qualname__)     # gives "my_function"
print(MyClass.method.__qualname__)  # gives "MyClass.method"

评论

0赞 dusio 11/29/2020
如果方法具有@property装饰器,则不起作用,在这种情况下,有什么方法可以访问名称?
3赞 lapis 11/30/2020
@dusiod,看起来您可以从属性的 getter(您使用 @property 装饰器创建)中获取名称/qualname:gives .MyClass.prop.fget.__qualname__MyClass.prop
22赞 Mohsin Ashraf 3/16/2018 #9

你只想得到函数的名称,这里有一个简单的代码。 假设您定义了这些函数

def function1():
    print "function1"

def function2():
    print "function2"

def function3():
    print "function3"
print function1.__name__

输出将为 function1

现在假设您在列表中拥有这些函数

a = [function1 , function2 , funciton3]

获取函数的名称

for i in a:
    print i.__name__

输出将是

函数 1
函数 2
函数 3

38赞 Ma Guowei 3/20/2019 #10
import inspect

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

哪里

  • stack()[0]是调用方

  • stack()[3]是方法的字符串名称

评论

2赞 kontur 10/28/2019
简单明了。 将始终是调用方,即方法的字符串名称。stack()[0][3]
16赞 NL23codes 10/25/2019 #11

我看过一些使用装饰器的答案,尽管我觉得有些有点冗长。这是我用来记录函数名称以及它们各自的输入和输出值的东西。我在这里对其进行了调整,使其仅打印信息而不是创建日志文件,并将其调整为适用于特定于 OP 的示例。

def debug(func=None):
    def wrapper(*args, **kwargs):
        try:
            function_name = func.__func__.__qualname__
        except:
            function_name = func.__qualname__
        return func(*args, **kwargs, function_name=function_name)
    return wrapper

@debug
def my_function(**kwargs):
    print(kwargs)

my_function()

输出:

{'function_name': 'my_function'}

评论

2赞 spareTimeCoder 4/15/2020
与所有其他函数相比,我喜欢这一点的是,只需添加一次函数,您就可以通过简单地将装饰器添加到您需要或想要打印函数名称的任何函数来添加功能。这似乎是最简单和适应性最强的。debug
1赞 Geraldo B. Landre 9/25/2021
为什么需要 try/except ?什么时候可以直接使用,什么时候不能使用?__qualname__
5赞 Ahmed Shehab 9/12/2020 #12

尝试

import sys
fn_name = sys._getframe().f_code.co_name

更多参考 https://www.oreilly.com/library/view/python-cookbook/0596001673/ch14s08.html

11赞 Szczerski 12/2/2020 #13
import inspect

def my_first_function():
    func_name = inspect.stack()[0][3]
    print(func_name)  # my_first_function

或:

import sys

def my_second_function():
    func_name = sys._getframe().f_code.co_name
    print(func_name)  # my_second_function
10赞 Gustin 2/6/2022 #14

您可以使用特殊变量以字符串形式获取函数的名称。__name__

def my_function():
    pass

print(my_function.__name__) # prints "my_function"

评论

0赞 Beefy_Swain 6/18/2023
这是新的,对吧?它是什么时候形成的?
1赞 Gustin 8/2/2023
@Beefy_Swain,至少从 Python 2.0(2000 年发布)开始,特殊变量就一直是该语言的一部分,并且可能可以追溯到 90 年代后期。__name__