Python 闭包与装饰器:初学者的完整指南
一、什么是闭包?
1. 作用域与变量访问
在 Python 中,变量的作用域分为两种:
全局作用域:在函数外部定义的变量
局部作用域:在函数内部定义的变量
访问规则:
*局部可以访问全局变量
*全局无法访问局部变量
为什么?因为 Python 的垃圾回收机制会在函数执行完毕后回收其内部变量,释放内存。
2. 闭包的定义
闭包是一种能在函数执行后保留其内部局部变量的技术。它本质上是一个嵌套函数,满足以下三个条件:
有嵌套:内部函数定义在外部函数内
有引用:内部函数使用了外部函数的变量
有返回:外部函数返回内部函数
例子:
def outer():
num = 20
def inner():
print(num)
return inner
f = outer() # f 现在是 inner 函数
f() # 输出 20
这样,即使 outer() 已经执行完毕,num 变量依然被保留,可以在全局中通过 f() 间接访问。
3. 修改外部变量
如果想在内部函数中修改外部函数的变量,需要使用 nonlocal 关键字:
def outer():
count = 0
def inner():
nonlocal count
count += 1
print(count)
return inner
f = outer()
f() # 输出 1
f() # 输出 2
4. 闭包判断
试着判断下面代码是否构成闭包,并思考输出结果:
def outer():
x = 10
def inner():
print(x)
return inner
f = outer()
f()
满足闭包的三个条件构成闭包,输出结果是10
二、什么是装饰器?
1. 装饰器的概念
装饰器是一种在不修改原函数代码和调用方式的前提下,为函数添加额外功能的技术。装饰器的本质就是一个闭包。
2. 装饰器的雏形
假设我们想为“评论”函数添加登录验证:
def check(fn):
def inner():
print("登录验证")
fn()
return inner
def comment():
print("评论功能")
comment = check(comment)
comment()
3. 使用 @ 语法糖
Python 提供了更简洁的写法:
def check(fn):
def inner():
print("登录验证")
fn()
return inner
@check
def comment():
print("评论功能")
comment()
2与3完全等价
4. 通用装饰器(支持任意参数和返回值)
为了让装饰器更灵活,我们使用 *args 和 **kwargs:
def logging(fn):
def inner(*args, **kwargs):
print("正在执行计算...")
return fn(*args, **kwargs)
return inner
@logging
def add(a, b):
return a + b
print(add(10, 20))
5. 带参数的装饰器
有时我们想通过装饰器传递参数,比如指定日志类型:
def logging(flag):
def decorator(fn):
def inner(*args, **kwargs):
if flag == '+':
print("执行加法运算")
elif flag == '-':
print("执行减法运算")
return fn(*args, **kwargs)
return inner
return decorator
@logging('+')
def add(a, b):
return a + b
print(add(5, 3))
三、练习
猜猜下面代码输出什么?
1、
def my_decorator(func):
def wrapper():
print("执行前")
func()
print("执行后")
return wrapper
@my_decorator
def say_hello():
print("Hello!")
say_hello()
2、
def log_args(func):
def wrapper(*args, **kwargs):
print(f"参数: {args}, {kwargs}")
return func(*args, **kwargs)
return wrapper
@log_args
def multiply(a, b):
return a * b
print(multiply(3, 4))
四、总结
闭包:允许在函数执行后保留局部变量,通过“嵌套+引用+返回”实现。
装饰器:基于闭包,用于在不修改原函数的情况下增强其功能,是 Python 中非常强大的语法特性。
通用装饰器:使用 *args 和 **kwargs 支持任意函数签名。
带参装饰器:通过外层函数接收参数,实现更灵活的功能扩展。
掌握闭包和装饰器,不仅能让你写出更优雅的代码,还能帮助你理解 Python 中许多高级特性(如 Flask 的路由装饰器)。多练习、多思考,你一定能熟练掌握它们!
更多推荐


所有评论(0)