欢迎光临
我们一直在努力

Python 函数终极进阶:闭包与装饰器,给函数穿上“马甲”

文章目

 

前言

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

1.1 什么是函数?

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

1.3 变量作用域

1.4 递归与高阶函数

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

2.1 什么是闭包?

2.2 闭包的条件

2.3 闭包有啥用?

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

3.1 装饰器长啥样?

3.2 装饰器的本质

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

3.4 多个装饰器叠加

3.5 装饰器常用场景

结尾

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

前言

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

闭包和装饰器是 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 闭包的条件

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

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

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

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

  • 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 糕手。🍻🐍

    —— 下个路口见。 👋

    赞(0)
    未经允许不得转载:171主机测评 » Python 函数终极进阶:闭包与装饰器,给函数穿上“马甲”
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址