Python 函数如何稳定地引用自身?
[原始版本中的代码乱七八糟。即使在我修复代码后,帖子中仍然有几个非常混乱的拼写错误。我相信我最终也修复了所有错误。非常抱歉。] 下面对Python 函数如何稳定地引用自身?,python,introspection,Python,Introspection,[原始版本中的代码乱七八糟。即使在我修复代码后,帖子中仍然有几个非常混乱的拼写错误。我相信我最终也修复了所有错误。非常抱歉。] 下面对alias的两个调用产生不同的输出,因为与变量my_own\u id关联的对象在两个调用之间发生变化: >>> def my_own_id(): ... me = my_own_id ... return id(me) ... >>> alias = my_own_id >>> alias()
alias
的两个调用产生不同的输出,因为与变量my_own\u id
关联的对象在两个调用之间发生变化:
>>> def my_own_id():
... me = my_own_id
... return id(me)
...
>>> alias = my_own_id
>>> alias()
4301701560
>>> my_own_id = None
>>> alias()
4296513024
在my_own_id
的定义中,我可以为me
分配什么,以便其输出在my_own_id
变量的后续重新定义中保持不变?(低,因此内部me
变量始终引用相同的函数对象?)
(我可以获取当前帧(使用inspect.currentframe()
),但它只包含对当前代码对象的引用,而不包含对当前函数的引用。)
另外,这个问题的动机只是为了更好地了解Python。事实上,如果您只依赖函数名,如果该名称在全局变量空间中被重写(在定义函数的模块中),那么使用函数名itslef的引用将失败 更简单、更易维护的方法是为此编写一个装饰器,它将提供一个
非局部变量,其中包含对函数本身的引用
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表达式:
这是由于范围的原因
>>> 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
>>>
>>def foo():
... x=foo
... 打印x
...
>>>foo()
>>>别名=foo
>>>别名()
>>>foo=无
>>>别名()
没有一个
>>>foo=[]
>>>别名()
[]
>>>德福
>>>别名()
回溯(最近一次呼叫最后一次):
文件“”,第1行,在
文件“”,第2行,在foo中
NameError:未定义全局名称“foo”
>>>
如果您不介意调用函数(将所需函数放入全局范围),可以包装函数以保护其定义:
>>> 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
请注意,受保护的函数必须使用非本地名称而不是全局名称来调用自身。装饰器方法可能是最好的方法。以下是更多有趣的内容:
劫持函数参数之一以提供静态变量
def fn(fnid=None):
print "My id:", fnid
fn.func_defaults = (id(fn),)
这里有几种获取当前函数的方法:;其中大多数涉及在各种位置搜索currentframe.f_代码。这些操作不需要对原始功能进行任何修改
似乎引用my_own\u id
将在全局命名空间字典中查找'my_own\u id'
,因此它将始终是函数定义中使用的名称。由于该名称可以指定给不同的值,因此检索到的值也可以更改。如果将me
设为默认参数,则可以在函数定义中将其指定给函数本身,以保留对实际函数的引用
您可以使用这个decorator,它隐式地将原始函数本身作为第一个参数传递
>>> 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
有一个想法,但似乎没有发展:使用一个可变的默认参数来保存函数对象中的值。定义函数时,默认参数值仅计算一次,并在之后保留其以前的值
>>> 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
这要求您务必小心,切勿使用参数调用函数。import inspect
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>
定义这个函数:
尝试:
frame=inspect.currentframe().f_back
代码=frame.f_代码
返回frame.f_globals[code.co_name]
最后:
删除代码
三角架
def myfunc(*参数):
打印这个
>>>myfunc(1)
>>>myfunc
垃圾邮件定义在哪里?
这个例子有点让人困惑-是ham
和spam
引用了my_own_id()
?很好的发现:-)[你应该编辑将my_own_id重命名为垃圾邮件的问题]我不知道为什么会发生这种情况。如果再次赋值,它将保持稳定:foo=ham;火腿();德尔哈姆;foo()
(我想这是你问题的答案,尽管没有任何洞察:-)这很有趣:>>>id(我自己的id)45375408>>别名=我自己的id>>>id(别名)45375408>>我自己的id=无>>id(我自己的id)5053544444>>id(别名)45375408>>别名(别名)5053544444
@MartijnPieters:我的代码搞错了;我现在已经修好了。很抱歉造成混淆。可能要更改名称,因为按照目前编写的方式,这不太管用:您定义own\u id
变量,但不使用它。呃,我认为这也不管用。。。非局部作用域仅在封闭作用域上工作,不通过调用方工作。因为my_own_id
的定义既不在know_thyself
的内部,也不在new_func
的内部;没有一个名字是可见的(除了一些框架检查shenanegans),我想问题不是为什么,而是如何规避。@Luke:是的,我知道。我也很好奇。我把答案留作将来参考。你真的试过了吗?我在Python2.6.1中得到了一个NameError;在解析参数时,名称my_own_id
还不存在。@RussellBorogove刚刚在2.6.5和2.7上试用过,似乎有效啊,我漏掉了my_own\u id=None
行。您得到的是None
,而不是函数的id。(我这里说的是你的第一节,不是装饰版。)@RussellBorogove哦,我要把这个解决方案去掉。我想我实际上可以得到object()
的id……这当然只适用于在重新分配名称之前调用函数的情况。@Dougal您可以将第一个调用放在定义之后,只是为了确保。是的,但是如果这是一个昂贵的函数调用,您不一定要这样做。只是指出这并不是万无一失的。很有趣,但正如你所说的,这是行不通的