目录
一、什么是闭包?
二、什么是装饰器?
三、练习
四、总结

一、什么是闭包?

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 的路由装饰器)。多练习、多思考,你一定能熟练掌握它们!

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐