Python 修饰器的一些小细节和使用技巧
前贴 /t/513929 中提到了 python 修饰器的一个疑问,经过一番研究终于明白了,总结了一下,然后就发出来了分享一下。与君共勉
"""
带参数修饰器会在初始化时就执行修饰器的代码并将方法体重新赋值给方法名。
"""
def deco1(args):
“”"
方法执行时不会再执行修饰器代码,因为该代码返回了方法本身
等价于:
def deco1(args):
print(“deco1:”,args)
return lambda fn:fn
test1=deco1(args=‘deco1args’)(mymethod)
:param args:
:return:
“”"
def decorator(fn):
print('deco1:', args)
return fn
return decorator
@deco1(“deco1args”)
def test1():
print(“test1”)
“”"
不带参数修饰器在初始化的时候会将方法名赋值给修饰器方法,修饰器方法内部来手动调用被修饰的方法。
“”"
def deco2(fn):
“”"
方法每次执行时都会执行修饰器因为 test2 重新赋值为修饰器的函数
等价于:
def deco2(fn):
def inFn():
print(‘deco2’)
fn()
return inFn
myMethod2 = deco2(lambda: print(“call myMethod2”))
:param fn:
:return:
“”"
def decorator():
print('deco2')
fn()
return decorator
@deco2
def test2():
print(“test2”)
def deco3(fn):
“”"
不会执行 fn 因为 fn 没有被调用
等价于:
def deco3(fn):
def inFn():
print(‘deco3’)
return fn
return inFn
test3=deco3(test3)
:return:
"""
def decorator():
print('deco3')
return fn
return decorator
@deco3
def test3():
print(“test3”)
if name == ‘main’:
print("-----开始执行 main 方法-----")
print("test1 每次调用都不会执行修饰器:")
test1()
print("")
test1()
print("======")
print("test2 每次调用都会执行修饰器:")
test2()
print("")
test2()
print("======")
print("test3 不会被执行:")
test3()
print("test3 的返回值才是 test3 方法,因此要这样执行:")
test3()()
“”"
“”"
print("-------等价函数------")
def eqDeco1(args):
print(“deco1:”, args)
return lambda fn: fn
print(“deco1 的等价:”)
myMethod = eqDeco1(args=‘deco1args’)(lambda: print(“call myMethod1”))
myMethod()
def eqDeco2(fn):
def inFn():
print(‘deco2’)
fn()
return inFn
myMethod2 = eqDeco2(lambda: print(“call myMethod2”))
myMethod2()
def eqDeco3(fn):
def inFn():
print(‘deco3’)
return fn
return inFn
myMethod3 = eqDeco3(lambda: print(“call myMethod3”))
myMethod3()
myMethod3()()
执行结果
deco1: deco1args
-----开始执行 main 方法-----
test1 每次调用都不会执行修饰器:
test1
test1
test2 每次调用都会执行修饰器:
deco2
test2
deco2
test2
test3 不会被执行:
deco3
test3 的返回值才是 test3 方法,因此要这样执行:
deco3
test3
-------等价函数------
deco1 的等价:
deco1: deco1args
call myMethod1
deco2
call myMethod2
deco3
deco3
call myMethod3
Python 修饰器的一些小细节和使用技巧
Python 装饰器:核心细节与实用技巧
装饰器本质上是高阶函数,它接受一个函数作为参数并返回一个新函数。理解这一点是关键。
1. 基础结构与执行时机 装饰器在函数定义时立即执行,而不是在函数调用时。看看这个:
def my_decorator(func):
print("装饰器执行了!")
def wrapper():
print("函数调用前")
func()
print("函数调用后")
return wrapper
@my_decorator
def say_hello():
print("Hello!")
# 输出:装饰器执行了!
# 此时say_hello已经是wrapper函数了
say_hello()
# 输出:
# 函数调用前
# Hello!
# 函数调用后
2. 保留元信息
使用@functools.wraps避免丢失原函数的__name__等属性:
import functools
def debug(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
print(f"调用 {func.__name__}")
return func(*args, **kwargs)
return wrapper
3. 带参数的装饰器 需要三层嵌套:
def repeat(num_times):
def decorator(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
for _ in range(num_times):
result = func(*args, **kwargs)
return result
return wrapper
return decorator
@repeat(num_times=3)
def greet(name):
print(f"Hello {name}")
4. 类装饰器
通过实现__call__方法让类可调用:
class CountCalls:
def __init__(self, func):
self.func = func
self.num_calls = 0
def __call__(self, *args, **kwargs):
self.num_calls += 1
print(f"调用次数: {self.num_calls}")
return self.func(*args, **kwargs)
@CountCalls
def example():
print("函数执行")
5. 装饰器叠加顺序 装饰器从下往上应用:
@decorator1
@decorator2
def func():
pass
# 等价于:func = decorator1(decorator2(func))
实用技巧:
- 用
*args, **kwargs确保装饰器通用 - 调试时可以在装饰器内打印参数和返回值
- 缓存、日志、权限检查是装饰器的典型应用场景
总结:理解装饰器的执行时机和嵌套结构是关键。
嗯 装饰器就是函数重新赋值的语法糖。

