前言

函数这块我们已经聊了好几期了,从最基础的“什么是函数”,到参数的各种花式传法,再到作用域、递归、高阶函数……今天终于来到了函数系列的收官之战

闭包装饰器是 Python 里两个“听起来很高级、用起来很优雅”的概念。

        闭包:让函数“记住”它诞生时的环境,即使离开了那个环境,记忆还在。

         装饰器:在不修改原函数代码的前提下,给函数“穿上马甲”增加新功能,俗称“偷懒界的扛把子”。

学完今天这一篇,你的代码不仅跑得快,还长得好看。Python 里的 @staticmethod@classmethod、Flask 里的 @app.route(),全是装饰器的杰作。

先花 30 秒快速回顾一下前面讲过的函数知识,然后重点攻克闭包和装饰器。开整!🧵

第一章:函数基础快速回顾(思路清晰整理基础)

1.1 什么是函数?

函数就是把一段代码打包,起个名字,随时调用。写一次用无数次,告别 Ctrl+C/V。

python

def greet(name):
    return f"你好,{name}!"

1.2 函数的参数(四种传法)

参数类型 说明 示例
位置参数 按顺序传 greet("王小明", 18)
默认参数 不传就用默认值 def greet(name, age=18)
关键字参数 指名道姓传 greet(age=20, name="小红")
可变参数 收不定数量的参数 *args 收元组,**kwargs 收字典

python

# 万能参数模板
def super_func(*args, **kwargs):
    print("位置参数们:", args)    # 元组
    print("关键字参数们:", kwargs) # 字典

super_func(1, 2, 3, name="小明", age=18)

1.3 变量作用域

关键字 作用
global 在函数里修改全局变量
nonlocal 在嵌套函数里修改外层函数的变量

1.4 递归与高阶函数

                递归:函数自己调自己,必须设终止条件

                高阶函数:把函数当参数传来传去,比如 map()filter()sorted()

第二章:闭包 —— 函数里的“记忆面包”

2.1 什么是闭包?

闭包就是在一个函数内部定义了另一个函数,并且内部函数使用了外部函数的变量,然后外部函数把内部函数返回

听起来有点绕?直接看代码:

python

def outer(x):           # 外部函数
    def inner(y):       # 内部函数
        return x + y    # 内部函数使用了外部函数的 x
    return inner        # 把内部函数返回

# 创建闭包
add_5 = outer(5)        # outer(5) 返回 inner,并且 x=5 被“记住”了
print(add_5(3))         # 8  (5 + 3)
print(add_5(10))        # 15 (5 + 10)

add_10 = outer(10)      # 新建一个闭包,x=10
print(add_10(3))        # 13 (10 + 3)

📌 闭包的核心inner 函数“记住”了 outer 里的 x,即使 outer 已经执行完了,x 的值还活着,被 inner 随身携带。

就像你小时候妈妈给你织了一条围巾,里面带着妈妈的手温——就算妈妈不在身边,围巾里还留着她的温度。

2.2 闭包的条件

形成闭包需要满足三个条件:

  1. 函数嵌套:外层函数里定义了内层函数

  2. 内层引用外层变量:内层函数用了外层的变量

  3. 外层返回内层函数:外层函数把内层函数当作返回值返回

2.3 闭包有啥用?

闭包最常见的用途就是“保存状态”——让函数在执行完后还能记住一些东西。

💡 每次调用 counter() 都会创建一个新的闭包,里面的 count 是独立的。这就像你去银行开账户,每个账户都有自己的余额。

第三章:装饰器 —— 给函数“穿上马甲”

3.1 装饰器长啥样?

装饰器是 Python 里一个很酷的特性,它让你能在不修改原函数代码的前提下,给函数增加新的功能

python

def timer(func):
    import time
    def wrapper():
        start = time.time()
        func()
        end = time.time()
        print(f"执行耗时:{end - start:.4f} 秒")
    return wrapper

@timer   # 👈 装饰器语法糖
def slow_function():
    import time
    time.sleep(1)
    print("任务执行完毕")

slow_function()

输出:

text

任务执行完毕
执行耗时:1.0002 秒

📌 @timer 相当于执行了 slow_function = timer(slow_function),把原函数“包”了一层。

3.2 装饰器的本质

装饰器本质上就是一个高阶函数:它接收一个函数作为参数,返回一个新的函数(通常叫 wrapper),新函数里包裹了原函数,并在执行前后增加额外逻辑。

手写一个最简装饰器(无参数版):

python

def my_decorator(func):
    def wrapper():
        print("函数执行前——准备开工!")
        func()
        print("函数执行后——收工!")
    return wrapper

@my_decorator
def say_hello():
    print("你好呀!")

say_hello()

输出:

text

函数执行前——准备开工!
你好呀!
函数执行后——收工!

3.3 带参数的装饰器(装饰器工厂)

有时候你希望装饰器本身能接收参数,比如“重复执行 N 次”:

python

这样可以记录函数返回所需要用的时间

import time
from random import randint as sj
def jv(a):
    def zhs(*args):
        start = time.time()
        zj = a(*args)
        print(f"开始反馈时间开销")
        print(f"{time.time() - start}")
        return zj
    return zhs
def sy(x,y,z):

    x = x +y
    y = y +z
    z = z +x
    return  x + y + z
print(sy(10,20,30))

💡 带参数的装饰器等于再多包一层:索引jv() 先返回 zhs, 再装饰 sy(x,y,z)。

3.4 多个装饰器叠加

一个函数可以被多个装饰器同时装饰,执行顺序是从下往上

可以反应出来一个函数的消耗时长和运行具体时间

python

import time
from random import randint as sj
def jv(a):
    def zhs(*args):
        start = time.time()
        zj = a(*args)
        print(f"开始反馈时间开销")
        print(f"{time.time() - start}")
        return zj
    return zhs

import datetime
def cb(aa):
    def js(*ss):
        jg = aa(*ss)
        aaa = datetime.datetime.now().strftime("%Y年-%m月-%d日-%H时:%M分:%S秒")
        print(f"执行时间为{aaa} ,数据值有{ss},输出结果为{jg}")
        return jg

    return js
@cb
@jv
def sy(x,y,z):

    x = x +y
    y = y +z
    z = z +x
    return  x + y + z
print(sy(10,20,30))

3.5 装饰器常用场景

场景 装饰器名字(自拟) 作用
计时 @timer 统计函数执行时间
日志 @log 自动打印调用信息和参数
权限校验 @login_required 检查用户是否登录
缓存 @cache 缓存函数结果,避免重复计算
重试 @retry 失败后自动重试 N 次
限流 @rate_limit 控制函数调用频率

🎯 闭包与装饰器对比

闭包 装饰器
本质 函数嵌套 + 引用外部变量 闭包的一种“语法糖”应用
目的 让函数记住状态 给函数加功能,不改原代码
语法 手动返回内层函数 用 @ 符号,更优雅
例子 计数器、配置工厂 @timer@log@login_required

结尾

到今天为止,你的函数技能树已经点满了:

                基础:定义、调用、参数、返回值

                进阶:作用域、递归、高阶函数、lambda

                高级:闭包、装饰器

闭包让函数“带记忆”,装饰器让函数“穿马甲”——这两个东西组合起来,你在 Python 世界里已经可以横着走了。

你现在能看懂那些 @app.route('/') 是咋回事了,能自己写一个 @timer 量一下哪段代码跑得慢,还能写一个 @login_required 拦住没登录的用户。

python

# 收工前的彩蛋:你自己也能写出这种“看起来很牛”的代码
@timer
@log
def your_first_decorated_func():
    print("你已经是进阶选手了!")

走到这一步,函数这块你已经不是新手了。后面再遇到新东西,你会感觉“万变不离其宗”。

🎁 彩蛋:写给一路打怪升级的你

好,说真的——

如果你是从 print("Hello World") 那一篇一直跟到现在的,那你自己可能没意识到,但你已经在 Python 这条路上走了挺远了。

从最开始连“环境变量”是啥都得查半天,到今天 闭包看得懂,装饰器写得出来,还给函数穿上马甲……你回头看看第一篇,你会发现自己早就不是那个连 int() 和 str() 都分不清的小白了。

函数这块学完,相当于你王者荣耀里把“法师”这个位置彻底练透了——走位、技能连招、支援节奏,全都有数了。后面再学面向对象、模块、异常处理、文件操作,都会觉得:“哦,原来是这么回事。”

Python 的函数写得好的程序员,写出来的代码读起来像说话一样流畅,逻辑是顺的,层次是清的,别人接手你的代码会忍不住说一句:“这代码写得真舒服。”

这句话,早晚有一天会落到你头上。

不急,按自己的节奏慢慢来,代码这东西,你越写越有感觉,越写越顺手。今天搞懂一个概念,明天就多一个武器。

写代码不是靠天赋,是靠“搞懂了之后再敲几遍”。
你敲过的每一行代码,都在帮你从“看得懂”走向“写得出”,再到“写得好”。

你现在站在函数这一关的终点,也是面向对象那一关的起点。前方还有新地图,你手里的剑已经够亮了。

去敲吧,Python 糕手。🍻🐍

—— 下个路口见。 👋

Logo

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

更多推荐