一、函数和闭包的区别
函数:函数是一段可重复使用的代码,它可以接受输入参数并返回结果。函数在定义时不会记住任何数据或状态。
闭包:闭包是一种特殊的函数,它记住了其外部函数的局部变量值。这意味着即使外部函数已经返回,闭包仍然可以访问和修改这些变量。
可以举一个形象的例子:函数和闭包就像是紫菜包饭和寿司,一个馅是在里面,而另一个在外面。
def outer_function(x):
def inner_function(y):
return x + y
return inner_function
add_five = outer_function(5)
print(add_five(10)) # 输出:15
这里就是一个闭包的例子,我们定义了一个函数叫outer,在outer里定义了一个内部函数inner。而里面的inner可以使用外部函数outer的x变量,这样可以防止全局变量的滥用,而最外层的add_five则是一个闭包。你可以理解成,add_five是outer函数的一个‘实例’,经过add_five = outer_function(5)
之后,这个add_five就变成了一个函数(期待输入inner的y参数)。
装饰器
而装饰器的作用也有相似之处:装饰器本质上是一个接收函数作为参数并返回一个新函数的函数。
这里的@my_decorator
是一种简单的表示装饰器的方法 。
def my_decorator(func):
def wrapper():
print("Before function call")
func()
print("After function call")
return wrapper
@my_decorator
def say_hello():
print("Hello!")
say_hello()
当我们调用say_hello()
时,Python会自动将 say_hello
函数作为参数传递给 my_decorator
函数,然后用 my_decorator
函数的返回值(即 wrapper
函数)替换 say_hello
函数。实际上我们调用的是 wrapper
函数。因此,输出会是:
Before function call
Hello!
After function call
因此,我们可以说 my_decorator
装饰了 say_hello
函数。在这个过程中,say_hello
函数的行为被修改了:当我们调用 say_hello()
时,实际上我们调用的是 wrapper
函数,它在调用原始的 say_hello
函数之前和之后打印了一些消息。
闭包和装饰器
首先,装饰器和闭包都是高阶函数,即它们都是接收函数作为参数或返回函数的函数。
然而,它们用于解决的问题是不同的:装饰器用于修改函数或类的行为,而闭包用于记住函数的状态。也可以说,装饰器更进一步,它使用这些概念来修改或增强其他函数的行为。
同时我们可以发现,装饰器往往用到了闭包,这是因为装饰器要实现给函数添加行为这个功能,需要接受函数做参数,也需要返回新函数:
(1)装饰器通过接收一个函数作为参数,可以对这个函数进行包装或修改。
(2)装饰器通过返回一个新的函数,可以改变原函数的行为。这个新函数通常会调用原函数,并在调用前后添加一些额外的逻辑。
这两个特性使得装饰器需要使用闭包。
flask中的route
在使用flask框架时,总能发现一个叫route的装饰器,它的主要作用是将函数绑定到一个URL,当flask处理请求的时候,会检查其请求的URL,然后调用与这个URL关联的函数。
from flask import Flask
app = Flask(__name__)
@app.route('/')
def home():
return "Hello, World!"
if __name__ == '__main__':
app.run()
在这个例子中,@app.route('/')
装饰器将 home
函数绑定到了 URL '/'。
当你访问 http://localhost:5000/
(默认的地址和端口)时,Flask 会调用home
函数,并将其返回值作为 HTTP 响应发送给客户端。route() 装饰器内部的实现可能会比这个例子复杂得多,因为它需要处理各种各样的情况,如不同的 HTTP 方法(GET、POST 等)、动态路由、URL 转换等。但是,从最基本的层面来看,route() 装饰器就是一个使用了闭包的装饰器,它将 URL 路径映射到视图函数。