Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/batch-file/6.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 函数如何稳定地引用自身?_Python_Introspection - Fatal编程技术网

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您可以将第一个调用放在定义之后,只是为了确保。是的,但是如果这是一个昂贵的函数调用,您不一定要这样做。只是指出这并不是万无一失的。很有趣,但正如你所说的,这是行不通的