python函数装饰器

发布于:2025-04-03 ⋅ 阅读:(17) ⋅ 点赞:(0)

python函数装饰器

声明:博主并没有系统学习过python语言,在实际项目中遇到关于python不懂的语法,这里仅作为个人学习积累笔记

1.1 python函数相关基础

深入了解python函数装饰器移步:Python 函数装饰器
下面的笔记来源于上述链接
python中将函数赋值给变量,并不会执行该函数,函数只有加括号才会被调用

def hi():
   print("")

greet = hi # 函数hi不会被调用,只是将函数赋值给了变量
hi() # 函数会被执行
# 若要通过greet来执行hi函数
greet() # 变量变为了函数

函数中嵌套函数,所有的嵌套函数会被一同执行,并且嵌套函数不能被外界单独访问

def hi():
	def greet():
	    ……
	def welcome():
		 ……
hi() #调用函数hi()则greet() welcome()会被一同调用

函数中嵌套函数时,从中返回某个特定嵌套函数

def hi(name="func1"):
		def greet():
	    	……
		def welcome():
		 	……
		if name == "func1":
			 return greet
		else:
			 return welcome
a = hi() # 将hi()函数返回的函数赋值给a
print(a()) #调用a函数,即返回的greet函数

函数作为另一个函数的参数传入

def hi():
    ……

def func2(func1): 
    print(func1())
func2(hi) #将函数hi作为参数传入函数func2,在func2中执行hi函数

1.2 装饰器的核心作用

Python函数装饰器是一种高阶函数,其核心作用是在不修改原函数代码的情况下动态扩展函数功能。这种特性使得装饰器在代码复用、功能解耦、逻辑增强等方面具有独特优势。

简单了解装饰器的其中一个作用:
动态功能扩展:为函数添加额外行为
装饰器的核心能力是在不改变原函数内部代码的情况下,为其包裹新的功能逻辑
例如实现函数调用日志记录:

def log_decorator(func):
    def wrapper(*args,**kwargs):
        print(f"[LOG] 开始执行 {func.__name__},参数:{args}")
        result = func(*args,**kwargs)  # 调用原函数
        print(f"[LOG] {func.__name__} 执行完成,结果:{result}")
        return result
    return wrapper

@log_decorator  # 等价于 add = log_decorator(add) 将原函数add作为参数传递给log_decorator函数
def add(a, b):  # add变量被重新绑定为log_decorator(add)的返回值(即内部函数wrapper)
    return a + b

add(3, 5)
# 输出:
# [LOG] 开始执行 add,参数:(3, 5)
# [LOG] add 执行完成,结果:8

装饰器的应用阶段(代码加载时)当Python解释器加载@log_decorator语法时,会立即执行装饰器函数log_decorator:
函数调用阶段(运行时)当执行add(3, 5)时,实际调用的是被装饰后的wrapper函数
执行顺序

调用 add(3,5)
│
├─> 进入 wrapper(3,5)
│   ├─> 执行 [LOG] 开始执行 add,参数:(3,5)
│   ├─> 调用 func(3,5) → 原始add函数
│   │   └─> 计算 3+5=8
│   └─> 执行 [LOG] add 执行完成,结果:8
│
└─> 返回最终结果8

1.3 python函数装饰器的实际应用:请求限流

控制API调用频率:防止服务被恶意高频调用

def rate_limit(max_calls, period):
    def decorator(func):
        calls = []
        def wrapper(*args):
            now = time.time()
            # 清除超时记录
            calls[:] = [t for t in calls if now - t < period]
            if len(calls) >= max_calls:
                raise Exception("请求过于频繁")
            calls.append(now)
            return func(*args)
        return wrapper
    return decorator

@rate_limit(5, 60)  # 每分钟最多5次, rate_limit返回decorator, decorator接收api_request函数
def api_request():  # api_request = rate_limit(api_request)
    # 调用外部API

代码结构拆解,该代码通过装饰器工厂实现了一个滑动窗口请求限流器,其核心结构分为三层:

rate_limit(max_calls, period)#装饰器工厂,接收最大调用次数(max_calls)和时间周期(period秒),返回实际装饰器decorator
decorator(func)#接收被装饰函数(如api_request),通过闭包维护调用时间记录列表calls,返回包装函数wrapper
wrapper(*args)#实现限流逻辑,包含时间窗口清理、调用计数验证、异常抛出等核心功能


Python普通函数与闭包函数对比分析
普通函数
(1)独立定义,无嵌套结构
(2)每次调用均为独立上下文,无状态记忆能力

使用普通函数实现计数器
缺点:全局变量不安全,多实例无法并存

count = 0  # 全局变量易被篡改
def increment():
    global count
    count += 1
    return count
print(increment())  # 1
print(increment())  # 2

闭包函数
(1)嵌套函数结构,内部函数捕获外部函数变量
(2)通过闭包环境实现状态持久化

使用闭包函数实现计数器

def create_counter():
    count = 0
    def counter():
        nonlocal count
        count += 1
        return count
    return counter  # 每个实例独立计数
counter1 = create_counter()
counter2 = create_counter()
print(counter1())  # 1(实例1独立计数)
print(counter2())  # 1(实例2独立计数)