还在重复造轮子?这个语法让你的代码高级10倍
各位编程界的老铁们好啊。
今天要聊的这个玩意儿,叫装饰器。
听到这仨字你是不是已经头疼了。什么@classmethod、@property、@abstractmethod,满屏的@符号看着就让人犯困。
别怕。看完这篇文章,保证你不仅看懂,还能自己写。
先从为什么需要装饰器说起
想象这么个场景——你有10个函数,领导让你加个功能:每个函数执行前打印日志、记录执行时间、异常了发个告警。
你会怎么做。改10个函数。太蠢了。
装饰器就是来解决这个问题的——在不修改原函数的情况下,给函数加点额外的功能。
最简单的装饰器,只需要5行
defmy_decorator(func):
defwrapper(*args, **kwargs):
print("函数开始执行啦")
result = func(*args, **kwargs)
print("函数执行完啦")
return result
return wrapper
@my_decorator
defsay_hello(name):
print(f"Hello {name}!")
say_hello("混子哥")
输出:
函数开始执行啦
Hello 混子哥!
函数执行完啦
看到没。加上@my_decorator这一行,原函数什么都没变,但多了打印功能。
带参数的装饰器,才是真正的王者
基础版本太简单了,来看看怎么给装饰器本身传参数。
import time
deftimer(timeout=0):
defdecorator(func):
defwrapper(*args, **kwargs):
start = time.time()
result = func(*args, **kwargs)
elapsed = time.time() - start
if elapsed > timeout:
print(f"函数执行了 {elapsed:.2f} 秒,超过阈值 {timeout} 秒")
else:
print(f"函数执行了 {elapsed:.2f} 秒")
return result
return wrapper
return decorator
@timer(timeout=1)
defslow_function():
time.sleep(2)
return"done"
@timer(timeout=5)
deffast_function():
return"quick!"
slow_function()
fast_function()
输出:
函数执行了 2.00 秒,超过阈值 1 秒
函数执行了 0.00 秒
这个@timer(timeout=1)就是带参数的装饰器,比@timer高级多了。
多个装饰器叠加,效果太骚了
deflog(func):
defwrapper(*args, **kwargs):
print(f"[LOG] 调用 {func.__name__}")
return func(*args, **kwargs)
return wrapper
defuppercase(func):
defwrapper(*args, **kwargs):
result = func(*args, **kwargs)
return result.upper() if isinstance(result, str) else result
return wrapper
@log
@uppercase
defgreet(name):
returnf"hello {name}"
print(greet("tom"))
输出:
[LOG] 调用 wrapper
HELLO TOM
装饰器执行顺序是从下往上的,所以实际顺序是:greet → uppercase → log。
类装饰器,了解一下?
函数装饰器玩腻了。来试试类装饰器。
classCountCalls:
def__init__(self, func):
self.func = func
self.count = 0
def__call__(self, *args, **kwargs):
self.count += 1
print(f"函数被调用了 {self.count} 次")
return self.func(*args, **kwargs)
@CountCalls
deffibonacci(n):
if n <= 1:
return n
return fibonacci(n-1) + fibonacci(n-2)
fibonacci(5)
fibonacci(10)
fibonacci(5)
输出:
函数被调用了 1 次
函数被调用了 2 次
函数被调用了 3 次
实战场景来了,用装饰器简化Flask路由
from functools import wraps
from flask import request, jsonify
defvalidate_json(required_fields):
defdecorator(func):
@wraps(func)
defwrapper(*args, **kwargs):
ifnot request.is_json:
return jsonify({"error": "需要JSON数据"}), 400
data = request.get_json()
missing = [f for f in required_fields if f notin data]
if missing:
return jsonify({"error": f"缺少字段: {missing}"}), 400
return func(*args, **kwargs)
return wrapper
return decorator
@app.route('/user', methods=['POST'])
@validate_json(['name', 'email'])
defcreate_user():
return jsonify({"message": "用户创建成功"})
看,用装饰器处理参数验证,代码清爽多了。
混子哥的个人观点
说实话,装饰器这玩意儿看着吓人,用起来是真香。
一定要掌握的场景:
别乱用的场景:
常见标准库装饰器,你肯定见过
# property - 把方法变成属性
classUser:
@property
defname(self):
return self._name
# staticmethod - 静态方法
classMath:
@staticmethod
defadd(a, b):
return a + b
# classmethod - 类方法
classPerson:
@classmethod
deffrom_dict(cls, data):
return cls(**data)
# functools.lru_cache - 自动缓存
from functools import lru_cache
@lru_cache(maxsize=128)
defexpensive_calc(n):
return sum(range(n))
总结时间
记住:装饰器就是包装原函数,在不改变原函数的前提下添加新功能。搞懂这个,装饰器就没什么神秘的了。