我三者之间很困惑.我知道闭包是由另一个函数返回的函数,并且可以从封闭范围访问局部变量
例:
def add_nums(one):
def adder(two):
return one+two
return adder
a_10 = add_nums(10)
print a_10(5)
15
Run Code Online (Sandbox Code Playgroud)
在这里,adder是一个封闭.
但是,这也不是一个例子 partial
from functools import partial
a_10 = partial(add_nums, 10)
print a_10()(5)
15
Run Code Online (Sandbox Code Playgroud)
两者有什么区别?
此外,装饰器用于向函数添加功能.
def add_nums(one):
def adder(two):
print "foo, bar"
return one+two
return adder
a_10 = add_nums(10)
print a_10(5)
foo, bar
15
Run Code Online (Sandbox Code Playgroud)
这三者有什么区别?
简短回答: 闭包是机制,而functools.partial装饰器是该机制的典型用途.
闭包和更典型的命名空间之间的关键区别在于,当控制流离开顶级函数时,"封闭"命名空间中的名称和值不会消失.它们保存在与内部函数的一个实例相关联的迷你命名空间中,并且只要该实例存在,它就能存活下来.
functools.partial使用该能力"记住"预先存在的函数的一些参数.装饰者通常也出于同样的原因使用该能力.
请注意,装饰器比这更灵活.任何带有一个参数并返回一些东西的可调用都可以作为装饰器.它不具有充分利用Python的倒闭,甚至返回一个函数.许多装饰器返回一个可调用的对象.(另外,可以使用命名空间的对象和内部函数的方法来模拟闭包和内部函数.)
无论装饰器返回什么,都会分配给装饰函数所具有的名称.(在它们之后带有括号的装饰器,就像@decorator('args') ...稍微复杂一点.)典型的装饰器语法:
@decorator
def function():
pass
Run Code Online (Sandbox Code Playgroud)
...只是"定义,然后装饰和重新分配"的简写:
def function():
pass
function = decorator(function)
Run Code Online (Sandbox Code Playgroud)
对于一个极端(并且几乎无用)的例子:
def decorator5(__):
return 5
@decorator5
def square(x):
return x * x
print(square) # Prints 5 --- the function is gone.
square(10) # TypeError: 'int' object is not callable
Run Code Online (Sandbox Code Playgroud)
我认为您将实现与目的混淆了。创建一个封闭是一种做事的技术。您可以使用闭包来做很多事情。
在另一方面,partial并且decorator有特殊用途。也许他们使用闭包。也许他们没有。这是一个实现细节,您无需担心。重要的是他们要达到您想要的结果。
考虑一个partial。(忽略** kwargs。)创建它的一种方法是使用闭包:
def partial(f, *args):
def pf(*rest):
return f(*args, *rest)
return pf
Run Code Online (Sandbox Code Playgroud)
但这不是必须的。例如:
class Partial:
def __init__(self, func, args):
self.args = args
self.func = func
def __call__(self, *rest):
f = self.func
args = self.args
return f(*args, *rest)
def partial(f, *args):
return Partial(f, args)
Run Code Online (Sandbox Code Playgroud)
这里没有闭包,只有一个变量包含对其他变量的引用。但是我有部分行为,那么谁在乎呢?
装饰者也是如此。装饰器可能是闭包,也可能不是。例如,最近的一个问题涉及str.format在函数的__doc__字符串上运行。那只是接受功能对象,修改__doc__属性并返回相同对象的一种情况。显然,这不涉及任何关闭。
你的装饰器的部分版本实际上是:
def add_nums(one):
def adder(one, two):
return one + two
return partial(adder, one)
Run Code Online (Sandbox Code Playgroud)
请注意,嵌套函数现在仅使用显式参数,而不是闭包。您可以实现一个装饰器,它只是一个函数,它接受一个函数并返回一个(通常不同的)函数,使用闭包partial(使用闭包实现)或两者的混合。