简体   繁体   English

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

[英]How to get function object inside a function (Python)

I want to have something like我想要类似的东西

def x():
  print get_def_name()

but not necessarily know the name of x .但不一定知道x的名称。

Ideally it would return 'x' where x would be the name of the function.理想情况下,它会返回'x' ,其中 x 是函数的名称。

Functions in Python are objects, and as it happens those objects do have an attribute containing the name they were defined with: Python中的函数是对象,碰巧这些对象确实具有一个属性,其中包含使用它们定义的名称:

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

So, a naïve approach might be this: 因此,一个简单的方法可能是这样的:

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

That seems to work. 这似乎有效。 However, since you had to know the name of x inside the function in order to do that, you haven't really gained anything; 但是,由于您必须知道函数中x的名称才能执行此操作,因此您实际上并没有获得任何好处。 you might have well just have done this: 您可能已经做到了:

def x():
    print "x"

In fact, though, it's worse than that, because the __name__ attribute only refers to the name the function was defined with. 但是实际上,这比这更糟,因为__name__属性仅引用定义函数的名称。 If it gets bound to another name, it won't behave as you expect: 如果它绑定到另一个名称,它将无法按预期运行:

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

Even worse, if the original name is no longer around, it won't work at all: 更糟糕的是,如果原来的名称不再存在,它将根本无法使用:

>>> 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

This second problem is one you can actually get around, although it's not pretty. 第二个问题是您实际上可以解决的问题,尽管它并不漂亮。 The trick is to write a decorator that can pass the function's name into it as an argument: 诀窍是编写一个装饰器,该装饰器可以将函数名称作为参数传递给它:

>>> 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

... although as you can see, you're still only getting back the name the function was defined with, not the one it happens to be bound to right now. ...尽管如您所见,您仍然只返回定义该函数的名称,而不是现在刚绑定到的名称。

In practice, the short (and correct) answer is "don't do that". 实际上,简短(正确)的答案是“不要那样做”。 It's a fundamental fact of Python that objects don't know what name (or names) they're bound to - if you think your function needs that information, you're doing something wrong. Python的一个基本事实是对象不知道它们绑定的名称(或多个名称)-如果您认为函数需要该信息,那么您就在做错事。

You can do this by using Python's built-in inspect library. 您可以使用Python的内置检查库来执行此操作。

You can read more of its documentation if you want to handle more complicated cases, but this snippet will work for you: 如果您想处理更复杂的情况,可以阅读其更多文档,但是此代码段对您有用:

from inspect import getframeinfo, currentframe

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

print(test_func_name())

This sounds like you want to declare an anonymous function and it would return a reference to the new function object. 听起来您想声明一个匿名函数,它将返回对新函数对象的引用。

In Python, you can get a trivial anonymous function object with lambda but for a complex function it must have a name. 在Python中,您可以获得带有lambda的琐碎的匿名函数对象,但对于复杂的函数,它必须具有名称。 But any function object is in fact an object and you can pass references around to it, so the name doesn't matter. 但是实际上任何函数对象都是对象,您可以向其传递引用,因此名称无关紧要。

# 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

Note that this function does have a name, f , but the name doesn't really matter here. 请注意,此函数确实具有名称f ,但是这里的名称并不重要。 We set the name sqr to the function object reference and use that name. 我们将名称sqr设置为函数对象引用并使用该名称。 We could put the function reference into a list or other data structure if we wanted to. 如果需要,可以将函数引用放入列表或其他数据结构中。

You could re-use the name of the function: 您可以重用该函数的名称:

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

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

So, while Python doesn't really support full anonymous functions, you can get the same effect. 因此,尽管Python并不真正支持完整的匿名函数,但您可以获得相同的效果。 It's not really a problem that you have to give functions a name. 您不必给函数起一个名字,这并不是一个真正的问题。

If you really don't want the function to have a name, you can unbind the name: 如果您确实不希望函数具有名称,则可以取消绑定该名称:

def f(n):
    return n**2

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

Now the only way to access this function is through the list; 现在,访问此功能的唯一方法是通过列表。 the name of the function is gone. 函数的名称消失了。

I found a similar solution as Vazirani's, but I did a step forward to get the function object based on the name.我找到了与 Vazirani 类似的解决方案,但我向前迈了一步,根据名称获取函数对象。 Here is my solution:这是我的解决方案:

import inspect

def named_func():
    func_name = inspect.stack()[0].function
    func_obj = inspect.stack()[1].frame.f_locals[func_name]
    print(func_name, func_obj, func_obj.xxx)

named_func.xxx = 15
named_func()

Output is输出是

named_func <function named_func at 0x7f3bc84622f0> 15

Unfortunately I cannot do this with lambda function.不幸的是,我不能用 lambda 函数做到这一点。 I keep trying.我一直在努力。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM