如何在函数内部获取函数对象(Python)

时间:2014-06-16 18:42:50

标签: python function python-2.7 introspection

我想要像

这样的东西
def x():
  print get_def_name()

但不一定知道x的名称。

理想情况下,它会返回'x',其中x将是函数的名称。

3 个答案:

答案 0 :(得分:7)

Python中的函数是对象,当这些对象发生时,它们的属性包含它们所定义的名称:

>>> def x():
...     pass
...
>>> print x.__name__
x

所以,一种天真的方法可能就是这样:

>>> def x():
...     print x.__name__
... 
>>> x()
x

这似乎有效。但是,由于你必须知道函数内部x的名称才能做到这一点,你还没有真正获得任何东西;你可能已经做到了这一点:

def x():
    print "x"

事实上,它比这更糟糕,因为__name__属性仅指函数定义的名称。如果它被绑定到另一个名称,它将不会按预期运行:

>>> y = x
>>> y()
x

更糟糕的是,如果原始名称不再存在,则根本不起作用:

>>> del x
>>> y()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 2, in x
NameError: global name 'x' is not defined

第二个问题是你可以实际解决的问题,虽然它并不漂亮。诀窍是编写一个可以将函数名称作为参数传递给它的装饰器:

>>> from functools import wraps
>>> def introspective(func):
...     __name__ = func.__name__
...     @wraps(func)
...     def wrapper(*args, **kwargs):
...         return func(__name__=__name__, *args, **kwargs)
...     return wrapper
... 
>>> @introspective
... def x(__name__):
...     print __name__
... 
>>> x()
x
>>> y = x
>>> y()
x
>>> del x
>>> y()
x

...虽然你可以看到,你仍然只是回到了定义函数的名称,而不是现在碰巧绑定的名称。

在实践中,简短(和正确)的答案是“不要那样做”。 Python的一个基本事实是,对象不知道它们是什么名称(或名称)必然 - 如果你认为你的功能需要这些信息,你就会做错事。

答案 1 :(得分:2)

您可以使用Python的内置检查库来做到这一点。

如果您想处理更复杂的情况,可以阅读其更多文档,但是此代码段对您有用:

from inspect import getframeinfo, currentframe

def test_func_name():
    return getframeinfo(currentframe()).function

print(test_func_name())

答案 2 :(得分:0)

这听起来像是要声明一个匿名函数,它会返回对新函数对象的引用。

在Python中,您可以使用lambda获得一个简单的匿名函数对象,但对于复杂函数,它必须具有名称。但是任何函数对象实际上都是一个对象,您可以将引用传递给它,因此名称并不重要。

# lambda
sqr = lambda n: n**2
assert sqr(2) == 4
assert sqr(3) == 9

# named function
def f(n):
    return n**2

sqr = f
assert sqr(2) == 4
assert sqr(3) == 9

请注意,此函数的名称为f,但名称在此处并不重要。我们将名称sqr设置为函数对象引用并使用该名称。如果我们愿意,我们可以将函数引用放入列表或其他数据结构中。

您可以重复使用该功能的名称:

def f(n):
    return n**2
sqr = f

def f(n):
    return n**3
cube = f

因此,虽然Python并不真正支持完整的匿名函数,但您可以获得相同的效果。你必须给函数命名,这不是一个真正的问题。

如果您真的不希望该功能有名称,您可以取消绑定名称:

def f(n):
    return n**2

lst = [f]  # save function reference in a list
del(f)  # unbind the name

现在访问此功能的唯一方法是通过列表;函数的名称已经消失。