标题:闭包 · 装饰器 · 深浅拷贝——Python「高阶三剑客」一日通 #Day4
·
大家好,我是 亦难。
昨天我们用面向对象思想把“学生报名”和“小明减肥”两个场景全部代码化,今天继续进阶,一次性搞定 闭包、装饰器、深浅拷贝 这三件让新手头秃的“高阶三剑客”。读完你能:
① 用闭包把函数变量“续命”;
② 用装饰器给任何函数零侵入加功能;
③ 一眼看穿深浅拷贝的内存陷阱。
1️⃣ 闭包:让局部变量“长生不老”
作用
普通函数调用完就销毁局部变量,闭包能把变量“锁”在内存里,继续累加或做后续操作。
构成条件(一句话背下来)
有嵌套、有引用、有返回
最小可运行示例
def func_out(num1):
def func_inner(num2):
return num1 + num2 # 内部函数引用外部变量
return func_inner # 返回内部函数名
add_10 = func_out(10) # 闭包实例
print(add_10(1)) # 11
print(add_10(2)) # 12
nonlocal:在闭包里修改外部变量
def counter():
count = 0
def incr():
nonlocal count
count += 1
return count
return incr
c = counter()
print(c(), c(), c()) # 1 2 3
2️⃣ 装饰器:零侵入给函数加外挂
作用
不改动原函数源码的前提下,动态增加功能(日志、计时、权限校验等)。
构成条件(升级版闭包)
有嵌套、有引用、有返回、有额外功能
语法糖写法(最常用)
import time
def timing(fn):
def inner(*args, **kwargs):
start = time.time()
result = fn(*args, **kwargs)
print(f"{fn.__name__} 耗时 {time.time()-start:.4f}s")
return result
return inner
@timing
def slow_add(a, b):
time.sleep(0.5)
return a + b
print(slow_add(1, 2))
# 输出:slow_add 耗时 0.5003s
# 3
万能模板(通用装饰器)
from functools import wraps
def universal_decorator(func):
@wraps(func) # 保留原函数元数据
def wrapper(*args, **kwargs):
# 前置逻辑
print("前置处理")
result = func(*args, **kwargs)
# 后置逻辑
print("后置处理")
return result
return wrapper
3️⃣ 多个装饰器 & 带参装饰器
多个装饰器堆叠
执行顺序:离函数最近的先装饰、由内到外
@check_login
@check_code
def comment():
print("发表评论")
等价于
comment = check_login(check_code(comment))
带参装饰器(三层嵌套)
def log(flag): # 第 1 层收参数
def decorator(fn): # 第 2 层收函数
def inner(*a, **k): # 第 3 层收实参
print(f"[{flag}] 开始执行")
return fn(*a, **k)
return inner
return decorator
@log("DEBUG")
def add(a, b):
return a + b
print(add(1, 3))
# [DEBUG] 开始执行
# 4
4️⃣ 深浅拷贝:一张图看懂内存陷阱
| 场景 | 图示 | 结果 |
|---|---|---|
| 赋值 | a = b |
同一对象,同 id |
| 浅拷贝 | copy.copy() |
外层新对象,内层引用 |
| 深拷贝 | copy.deepcopy() |
全部层级全新对象 |
代码验证
import copy
lst1 = [[1, 2], 3]
lst2 = copy.copy(lst1) # 浅拷贝
lst3 = copy.deepcopy(lst1) # 深拷贝
lst1[0].append(999)
print(lst2) # [[1, 2, 999], 3] 内层被改
print(lst3) # [[1, 2], 3] 完全独立
5️⃣ 今日实战:日志装饰器 + 深拷贝防御性编程
需求:给任意函数加日志,同时把可变参数深拷贝一份防止原数据被误改。
import copy, functools, time
def safe_log(flag):
def decorator(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
# 深拷贝可变参数
cp_args = copy.deepcopy(args)
cp_kwargs = copy.deepcopy(kwargs)
start = time.time()
result = func(*cp_args, **cp_kwargs)
print(f"[{flag}] {func.__name__} 耗时 {time.time()-start:.4f}s")
return result
return wrapper
return decorator
@safe_log("API")
def risky_process(data):
data.append("修改")
return data
lst = [1, 2, 3]
print(risky_process(lst)) # 返回新数据
print(lst) # 原数据保持不动
🚩 明日预报
《从三次握手到聊天室:Python 网络编程 30 分钟上手》
我们将用 socket 手写 TCP 客户端 + 服务端,带你跑通 三次握手、四次挥手、端口复用、粘包拆包 全套流程,明晚 21:00 见!
更多推荐
所有评论(0)