Python 调用其参数的内置装饰器?
Python builtin decorator that calls its argument?
我正在寻找的是一个调用它的参数的函数,这样我就可以将它用作装饰器来轻松处理闭包。写起来很容易(如果我愿意的话,我什至可以使用 *args
和 **kwargs
):
def unclosure(f):
return f()
@unclosure
def count():
x = 0
def _count():
nonlocal x
x += 1
return x
return _count
assert count() == 1
assert count() == 2
但我觉得这是一个非常简单的想法,所以 必须 内置到 python 标准库的某个地方。我已经检查了 functools
,但我不知道还有什么地方可以检查,而且我似乎无法找到正确的内容来输入 google。有人知道 if/where 这个存在吗?
这通常会使用 class 而不是闭包来实现。
class Count:
def __init__(self):
self.x = 0
def __call__(self):
self.x += 1
return self.x
count = Count()
assert count() == 1
assert count() == 2
您要求的与1 apply
函数相同,该函数存在于 Python 从 1.0 到 2.7 的版本中,但已被弃用2.3.2
其实在2.7中也可以这样使用:
@apply
def count():
x=[0]
def _count():
x[0] += 1
return x[0]
return _count
assert count() == 1
assert count() == 2
为什么它被弃用了?
Python 并不经常需要它。当与 Python 没有的其他东西(如组合运算符)结合使用时,它在函数式语言中很有用,可以编写一种读起来不太 Python 且执行速度非常慢的代码风格。
但在 2.3 之前,情况并非如此。琐碎的情况,你可以自己写:lambda f: f()
,或者def apply(f): return f()
。但是对于非平凡的例子,在解包语法之前,你不能对参数做 "perfect forwarding",所以你不能模拟 apply
的每次使用。这就是添加它的原因。而且,一旦不再需要它,它就被弃用了。
有些人确实抱怨说自己编写它比使用 C 内置程序稍微慢一些——但是没有人想出一个用例来产生不同,但是额外的函数调用间接并没有使整个事情一开始就太慢了,无法使用。如果您查看从 Python 2.3-2.6 编写的大量开源代码,就会发现其中几乎 none 使用了 apply
。并且没有人编写和发布 C 扩展来保留或 apply
以便他们可以继续使用它。在过去的十年里,也没有人为 3.x 写过一篇文章。
当讨论 "Python 3000"(后来成为 3.0)时,首先想到的事情之一就是消除所有已弃用的功能。其中包括未弃用的内容,但 Guido 认为没有必要,例如 reduce
。您可以阅读邮件列表档案,了解人们出来捍卫某些功能和构造,通常是成功的 — 但我不记得,也找不到任何人试图捍卫 apply
。唯一的讨论是PEP 3100中的总结:
apply()
: use f(*args, **kw)
instead [2]
… 其中 link 指向(一个损坏的 link 到)Guido 的 Python Regrets presentation,它没有比称它为 "relic".[=26 更多的参数=]
1.或者,更确切地说,是 apply
的较弱版本,它不接受任何参数。
2。 IIRC(我找不到相关文档),这发生在 Python 真正理解 "deprecated" 之前。它被标记为 "non-essential" 并移至文档页面的末尾,并且仅在 2.5 或 2.6 左右的某个地方自 2.3 起被追溯弃用。
据我所知,标准库中不存在这样的函数。
我怀疑这是因为这样的功能几乎没有用例。甚至你的装饰器实际上也不是一个好的用例,因为它不是一个正确实现的装饰器。如您所见,它不维护函数的名称或文档字符串:
@unclosure
def count():
"""docstring"""
x = 0
def _count():
nonlocal x
x += 1
return x
return _count
print(count) # <function count.<locals>._count at 0x7f3282dac620>
print(count.__doc__) # None
也就是说在现实中应该这样实现:
import functools
def unclosure(f):
func = f()
functools.update_wrapper(func, f)
return func
@unclosure
def count():
"""docstring"""
x = 0
def _count():
nonlocal x
x += 1
return x
return _count
print(count) # <function count at 0x7f3892f7c620>
print(count.__doc__) # docstring
我正在寻找的是一个调用它的参数的函数,这样我就可以将它用作装饰器来轻松处理闭包。写起来很容易(如果我愿意的话,我什至可以使用 *args
和 **kwargs
):
def unclosure(f):
return f()
@unclosure
def count():
x = 0
def _count():
nonlocal x
x += 1
return x
return _count
assert count() == 1
assert count() == 2
但我觉得这是一个非常简单的想法,所以 必须 内置到 python 标准库的某个地方。我已经检查了 functools
,但我不知道还有什么地方可以检查,而且我似乎无法找到正确的内容来输入 google。有人知道 if/where 这个存在吗?
这通常会使用 class 而不是闭包来实现。
class Count:
def __init__(self):
self.x = 0
def __call__(self):
self.x += 1
return self.x
count = Count()
assert count() == 1
assert count() == 2
您要求的与1 apply
函数相同,该函数存在于 Python 从 1.0 到 2.7 的版本中,但已被弃用2.3.2
其实在2.7中也可以这样使用:
@apply
def count():
x=[0]
def _count():
x[0] += 1
return x[0]
return _count
assert count() == 1
assert count() == 2
为什么它被弃用了?
Python 并不经常需要它。当与 Python 没有的其他东西(如组合运算符)结合使用时,它在函数式语言中很有用,可以编写一种读起来不太 Python 且执行速度非常慢的代码风格。
但在 2.3 之前,情况并非如此。琐碎的情况,你可以自己写:lambda f: f()
,或者def apply(f): return f()
。但是对于非平凡的例子,在解包语法之前,你不能对参数做 "perfect forwarding",所以你不能模拟 apply
的每次使用。这就是添加它的原因。而且,一旦不再需要它,它就被弃用了。
有些人确实抱怨说自己编写它比使用 C 内置程序稍微慢一些——但是没有人想出一个用例来产生不同,但是额外的函数调用间接并没有使整个事情一开始就太慢了,无法使用。如果您查看从 Python 2.3-2.6 编写的大量开源代码,就会发现其中几乎 none 使用了 apply
。并且没有人编写和发布 C 扩展来保留或 apply
以便他们可以继续使用它。在过去的十年里,也没有人为 3.x 写过一篇文章。
当讨论 "Python 3000"(后来成为 3.0)时,首先想到的事情之一就是消除所有已弃用的功能。其中包括未弃用的内容,但 Guido 认为没有必要,例如 reduce
。您可以阅读邮件列表档案,了解人们出来捍卫某些功能和构造,通常是成功的 — 但我不记得,也找不到任何人试图捍卫 apply
。唯一的讨论是PEP 3100中的总结:
apply()
: usef(*args, **kw)
instead [2]
… 其中 link 指向(一个损坏的 link 到)Guido 的 Python Regrets presentation,它没有比称它为 "relic".[=26 更多的参数=]
1.或者,更确切地说,是 apply
的较弱版本,它不接受任何参数。
2。 IIRC(我找不到相关文档),这发生在 Python 真正理解 "deprecated" 之前。它被标记为 "non-essential" 并移至文档页面的末尾,并且仅在 2.5 或 2.6 左右的某个地方自 2.3 起被追溯弃用。
据我所知,标准库中不存在这样的函数。
我怀疑这是因为这样的功能几乎没有用例。甚至你的装饰器实际上也不是一个好的用例,因为它不是一个正确实现的装饰器。如您所见,它不维护函数的名称或文档字符串:
@unclosure
def count():
"""docstring"""
x = 0
def _count():
nonlocal x
x += 1
return x
return _count
print(count) # <function count.<locals>._count at 0x7f3282dac620>
print(count.__doc__) # None
也就是说在现实中应该这样实现:
import functools
def unclosure(f):
func = f()
functools.update_wrapper(func, f)
return func
@unclosure
def count():
"""docstring"""
x = 0
def _count():
nonlocal x
x += 1
return x
return _count
print(count) # <function count at 0x7f3892f7c620>
print(count.__doc__) # docstring