前言
在Python编程的进阶道路上,闭包和装饰器是两个不可或缺的高级特性。它们为代码提供了强大的灵活性和复用性,使得函数式编程在Python中得以广泛应用。本博客将深入剖析闭包与装饰器的概念、原理以及应用场景,帮助您更好地理解并掌握这两个强大的工具。无论您是Python初学者还是资深开发者,相信本文都能为您带来有价值的启示和收获。让我们一同探索Python闭包与装饰器的奥秘吧!
一、闭包是什么?
1.概念
1.内外函数嵌套
2.内函数引用外函数作用域下的非全局变量(嵌套作用域下的变量、外函数的参数)
3.外函数返回内函数对象(闭包可以返回内函数名,返回内函数调用)
2.定义
2.1 返回内函数引用
# 定义:第一种方式:返回内函数引用(内函数引用、内函数本身、内函数对象--->内函数名) def outer(): a = 10 def inner(): print(a) return inner # 调用 # outer() === inner # outer()() === inner() outer()()
2.2 返回内函数调用
# 定义:第二种方式:返回内函数调用 def outer1(a): def inner(): print(a) return inner() # 调用 # outer1() === inner() outer1(20)
二、装饰器
1.概念
装饰器作用:再不改变原函数的基础上给函数增加新的功能,利用了闭包的思路,本质上就是一个内部闭函数
2.使用
装饰器使用:想要装饰哪一个原函数就在哪个原函数上方编写 @装饰器名字
3.简单装饰器
# 简单装饰器功能实现 --》再进行自我介绍之前输出“请进行自我介绍” # 1.内外函数嵌套 def outer(f): # f == func def inner(): # 2.内函数引用外函数作用域下的非全局变量 print("请进行自我介绍") # 调用原函数-->函数名()-->f() === func() f() # 3.外函数返回内函数(内函数名、内函数调用) return inner # @outer === outer(原函数名)() @outer def func(): print("我是法外狂徒张三") func()
4.装饰带参数的原函数
4.1 结论
装饰带参数的原函数: \color{red}{装饰带参数的原函数:}装饰带参数的原函数:
1.内函数参数的数量要与原函数参数数量一致
2.内函数中原函数的调用参数的数量和参数名都要与内函数一致
4.2 普通参数
# 装饰器功能:再进行自我介绍前输出 "请进行自我介绍" # 1.内外函数嵌套 def outer(f): def inner(x,y): # 2.内函数引用外函数作用域下的非全局变量 print("请进行自我介绍") # 调用原函数 f(x,y) # 3.外函数返回内函数 return inner # 原函数功能:我叫xxx @outer def func(name,age): print(f"我叫{name},我今年{age}岁") func("李四",18)
4.3 不定长参数
# 装饰带不定长参数的原函数 # 装饰器功能:在打印和结果之前输出"开始进行求和操作",结果打印结束以后输出"求和完成" def outer(f): def inner(*args): print("开始进行求和操作") # 调用原函数 f(*args) print("求和完成") return inner # 原函数功能:实现用户任意传递两个数字,再函数内部输出和的结果 @outer def func(*args): # args元组里 print(f"求和的结果为:{sum(args)}") func(10,20,4,9,30,78,45,76,10)
5.装饰带返回值的原函数
# 装饰带返回值的原函数--》内函数中必须要有返回值 # 装饰器:在操作之间进行输出 请进行自我介绍 def outer(f): def inner(): print("请进行自我介绍") print(f()) return "hello" return inner # 原函数功能:进行自我介绍 返回 我叫张三 @outer def func(): return "我叫张三" print(func())
6.装饰带参数和返回值的原函数
# 装饰带参数和返回值的原函数 # 装饰器功能:在自我介绍前输出 “请开始自我介绍” 并要求输出的自我介绍需要增加p标签 def outer(f): def inner(x): print("请开始自我介绍") # 获取自我介绍的字符串-->调用原函数-->得到返回值 data = "<p>" + f(x) + "</p>" return data return inner # 原函数功能:返回自我介绍 "我叫xxx" 姓名让用户传参指定 @outer def func(name): return f"我叫{name}" print(func("李四"))
7.一个装饰器装饰多个原函数
import time # 一个装饰器装饰多个原函数 # 装饰器:统计运行时长,对时长进行判断,如果小于0.005则 非一般的速度,否则输出太慢了 def outer(f): def inner(): start = time.time() f() end = time.time() if end - start < 0.001: print("非一般的速度") else: print("太慢了") return inner # 原函数1:统计1988-2024之间的闰年,存放在列表中; # 判断区间内是否存在,存在则打印所有的闰年及数量;不存在则提示 @outer def func1(): list1 = [] for i in range(1988,2025): if i % 4 == 0 and i % 100 != 0 or i % 400 == 0: list1.append(i) if len(list1) > 0: print(list1) print(f"有{len(list1)}个满足条件的数据") else: print("区间内没有满足条件的数据") func1() # 原函数2:统计40-400之间的回文数,存放在列表中; # 判断区间内是否存在,存在则打印所有的回文数及数量;不存在则提示 @outer def func2(): list1 = [] for i in range(40,401): if str(i) == str(i)[::-1]: list1.append(i) if len(list1) > 0: print(list1) print(f"有{len(list1)}个满足条件的数据") else: print("区间内没有满足条件的数据") func2()
8.多个装饰器装饰一个原函数
# 多个装饰器装饰一个原函数 # 装饰器1:在调用原函数前输出 "装饰器1的开始";在调用原函数结束输出 "装饰器1的结束" def outer1(f): def inner(): print("装饰器1的开始") f() print("装饰器1的结束") return inner # 装饰器2:在调用原函数前输出 "装饰器2的开始";在调用原函数结束输出 "装饰器2的结束" def outer2(f): def inner(): print("装饰器2的开始") f() print("装饰器2的结束") return inner # 原函数 输出“我是原函数” @outer2 @outer1 def func(): print("我是原函数") func() # 总结: # 装饰器的调用顺序:从下往上 # 装饰器的执行顺序:从上往下 -->执行结果