[原始版本中的代码严重搞砸了。即使在我修改了代码之后,仍有几个高度混乱的错别字留在帖子中。我相信我终于修复了所有这些。深表歉意。]
下面对alias
的两次调用产生不同的输出,因为与变量my_own_id
相关联的对象在两次调用之间发生变化:
>>> def my_own_id():
... me = my_own_id
... return id(me)
...
>>> alias = my_own_id
>>> alias()
4301701560
>>> my_own_id = None
>>> alias()
4296513024
我可以在me
的定义中为my_own_id
分配什么,以便在后续重新定义my_own_id
变量时其输出保持不变? (IOW,以便内部me
变量总是引用相同的函数对象?)
(我可以获取当前帧(带inspect.currentframe()
),但它只包含对当前代码对象的引用,而不包含对当前函数的引用。)
P.S。这个问题的动机只是为了更好地了解Python。
答案 0 :(得分:3)
似乎引用my_own_id
将在全局命名空间字典中查找'my_own_id'
,因此它将始终是函数定义中使用的名称。由于该名称可以分配给不同的值,因此检索的值也可以更改。如果使me
成为默认参数,则可以在函数定义中将其分配给函数本身,以保持对实际函数的引用。
您可以使用此装饰器隐式传递原始函数本身作为第一个参数。
>>> from functools import wraps
>>> def save_id(func):
@wraps(func)
def wrapper(*args, **kwargs):
return func(func, *args, **kwargs)
return wrapper
>>> @save_id
def my_own_id(me): # me is passed implicitly by save_id
return id(me)
>>> alias = my_own_id
>>> alias()
40775152
>>> my_own_id = 'foo'
>>> alias()
40775152
答案 1 :(得分:2)
实际上,如果仅依赖函数名称,如果该名称在全局变量空间中被覆盖(在模块中定义了函数),则使用函数名称的引用将失败
更简单,更有效的方法是为它编写一个装饰器,它将提供一个包含对函数本身的引用的nonlocal
变量。
from functools import wraps
def know_thyself(func):
@wraps(func):
def new_func(*args, **kwargs):
my_own_id = func
return func(*args, **kwargs)
return new_func
可以用作:
>>> @know_thyself
... def my_own_id():
... me = my_own_id
... return id(me)
...
使用框架内省还有另一种可能的方法,远非如此干净 并重新使用相同的目标代码重建新函数。我在这篇文章中使用了这个 关于Python中的自引用lambda表达式: http://metapython.blogspot.com.br/2010/11/recursive-lambda-functions.html
答案 2 :(得分:1)
好吧,如果你不介意调用一个函数(将所需的函数放入全局范围),你可以包装函数来保护它的定义:
>>> def be_known():
... global my_own_id
... def _my_own_id():
... return id(_my_own_id)
... my_own_id = _my_own_id
...
>>> be_known()
>>> my_own_id()
140685505972568
>>> alias, my_own_id = my_own_id, None
>>> alias()
140685505972568
请注意,受保护的函数必须使用非本地名称而不是全局名称来调用自身。
答案 3 :(得分:1)
装饰者的方法可能是最好的方法。以下是一些有趣的内容:
劫持其中一个函数参数以提供静态变量。
def fn(fnid=None):
print "My id:", fnid
fn.func_defaults = (id(fn),)
有几种方法可以在这里获取当前函数:Python code to get current function into a variable?;其中大部分涉及在各种地方搜索currentframe.f_code。这些工作不需要对原始功能进行任何修改。
答案 4 :(得分:1)
import inspect
def _this_fn():
try:
frame = inspect.currentframe().f_back
code = frame.f_code
return frame.f_globals[code.co_name]
finally:
del code
del frame
def myfunc(*parms):
print _this_fn()
>>> myfunc(1)
<function myfunc at 0x036265F0>
>>> myfunc
<function myfunc at 0x036265F0>
答案 5 :(得分:0)
这是由于范围
>>> def foo():
... x = foo
... print x
...
>>> foo()
<function foo at 0x10836e938>
>>> alias = foo
>>> alias()
<function foo at 0x10836e938>
>>> foo = None
>>> alias()
None
>>> foo = []
>>> alias()
[]
>>> del foo
>>> alias()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 2, in foo
NameError: global name 'foo' is not defined
>>>
答案 6 :(得分:0)
Luke有一个想法,但似乎没有开发它:使用一个可变的默认参数来保存函数对象中的值。默认参数值仅在定义函数时计算一次,并在此之后保留其先前的值。
>>> def my_own_id(me=[None]):
if not me[0]:
me[0] = my_own_id
return id(me[0])
>>> alias = my_own_id
>>> alias()
40330928
>>> my_own_id = None
>>> alias()
40330928
您需要注意不要使用参数调用该函数。