Python34_装饰器知识

Python34_装饰器知识 Python34_装饰器知识文章目录Python34_装饰器知识[toc]1-核心知识2-装饰器代码示例3-辨识函数是否装饰器一、从代码结构辨识最核心1. 高阶函数特征2. 返回对象必须是可调用的二、从使用方式辨识1. 语法糖显性标识2. 手动调用形式等价写法三、从行为模式辨识1. 透明增强原则2. 是否包装Wrap原函数四、实用辨识技巧技巧 1用 inspect 检查技巧 2运行时验证五、常见混淆情况辨析六、一句话总结4-Python装饰器(Decorator)学习笔记 核心概念简单理解 装饰器的5个层次1️⃣ 基础装饰器2️⃣ 保留元信息 (使用wraps)3️⃣ 带参数的装饰器装饰器工厂4️⃣ 参数验证装饰器类似你的需求5️⃣ 实用装饰器示例 核心要点总结 运行示例1-核心知识装饰器代码代码示例 - 入参和返回值都【函数】如何辨识一个函数是装饰器 - 接收【函数】返回也必须是【函数】装饰器的3个层次 - 基础装饰器保留元信息带参数装饰器2-装饰器代码示例 Python装饰器(Decorator)核心概念学习 装饰器本质是一个接受函数作为参数并返回一个新函数的函数 # 第1层最基础的装饰器 defmy_decorator(func):装饰器本质包装原函数添加额外功能defwrapper():print( 装饰器函数调用前)resultfunc()# 调用原函数print( 装饰器函数调用后)returnresultreturnwrappermy_decoratordefsay_hello():print( Hello World!)# 第2层装饰器保留原函数的元信息 fromfunctoolsimportwrapsdefbetter_decorator(func):使用wraps保留原函数的名称、文档字符串等信息wraps(func)defwrapper(*args,**kwargs):print(f 调用函数:{func.__name__})returnfunc(*args,**kwargs)returnwrapperbetter_decoratordefgreet(name):向某人打招呼returnfHello,{name}!# 第3层带参数的装饰器装饰器工厂 defrepeat(times): 带参数的装饰器工厂 返回一个真正的装饰器 defdecorator(func):wraps(func)defwrapper(*args,**kwargs):results[]foriinrange(times):print(f 第{i1}次调用)resultfunc(*args,**kwargs)results.append(result)returnresultsreturnwrapperreturndecoratorrepeat(times3)defsay_hi(name):returnfHi,{name}!# 第4层类似你提到的参数验证装饰器 deftool_parameters(parameters): 类似TypeScript中 tool_parameters 的Python实现 验证函数参数的类型和必需性 defdecorator(func):wraps(func)defwrapper(**kwargs):# 获取参数定义propertiesparameters.get(properties,{})requiredparameters.get(required,[])# 验证必需参数forparaminrequired:ifparamnotinkwargs:raiseValueError(f缺少必需参数: {param})# 验证参数类型forparam_name,param_valueinkwargs.items():ifparam_nameinproperties:expected_typeproperties[param_name].get(type)actual_typetype(param_value).__name__# 类型映射type_mapping{str:str,int:int,float:float,bool:bool,list:list,dict:dict}ifexpected_typeintype_mapping:expected_python_typetype_mapping[expected_type]ifnotisinstance(param_value,expected_python_type):raiseTypeError(f参数 {param_name} 类型错误: f期望{expected_type}, 实际{actual_type})# 验证通过调用原函数returnfunc(**kwargs)returnwrapperreturndecorator# 使用示例tool_parameters({type:object,properties:{path:{type:str},count:{type:int}},required:[path],})defread_file(path,count1):模拟读取文件returnf读取文件:{path}, 次数:{count}tool_parameters({type:object,properties:{user_id:{type:int},username:{type:str},active:{type:bool}},required:[user_id,username],})defcreate_user(user_id,username,activeTrue):模拟创建用户return{id:user_id,name:username,active:active}# 第5层带返回值的装饰器 defmeasure_time(func):测量函数执行时间importtimeimporttimeastime_modulewraps(func)defwrapper(*args,**kwargs):starttime_module.time()resultfunc(*args,**kwargs)endtime_module.time()print(f⏱️{func.__name__}执行时间:{end-start:.4f}秒)returnresultreturnwrappermeasure_timedefslow_function():模拟耗时操作importtime time.sleep(0.1)return完成# 运行所有示例 defmain():print(*60)print( Python装饰器核心概念学习)print(*60)print(\n1️⃣ 基础装饰器:)say_hello()print(\n2️⃣ 保留元信息的装饰器:)print(f 结果:{greet(Alice)})print(f 函数名:{greet.__name__})print(f 文档:{greet.__doc__})print(\n3️⃣ 带参数的装饰器重复3次:)resultssay_hi(Bob)print(f 结果:{results})print(\n4️⃣ 参数验证装饰器:)# 正确调用try:resultread_file(path/path/to/file,count2)print(f ✅ 正确调用:{result})except(ValueError,TypeError)ase:print(f ❌ 错误:{e})# 缺少必需参数try:resultread_file(count2)print(f 结果:{result})except(ValueError,TypeError)ase:print(f ❌ 缺少必需参数:{e})# 类型错误try:resultread_file(path123)# path应该是字符串print(f 结果:{result})except(ValueError,TypeError)ase:print(f ❌ 类型错误:{e})print(\n5️⃣ 创建用户参数验证:)try:usercreate_user(user_id1,usernameTom,activeFalse)print(f ✅ 创建成功:{user})except(ValueError,TypeError)ase:print(f ❌ 错误:{e})print(\n6️⃣ 测量执行时间:)resultslow_function()print(f 结果:{result})print(\n*60)print( 学习完成)print(*60)if__name____main__:main()3-辨识函数是否装饰器辨识一个函数是否是装饰器可以从代码结构特征、使用方式、行为模式三个维度来判断。以下是系统化的辨识方法一、从代码结构辨识最核心装饰器在代码层面有明确的结构指纹1. 高阶函数特征装饰器一定是高阶函数Higher-Order Function即接收函数作为参数返回函数或可调用对象# 典型的装饰器结构def装饰器名(func):# ← 参数是一个函数defwrapper(*args,**kwargs):# 增强逻辑...returnfunc(*args,**kwargs)# ← 调用并返回原函数结果returnwrapper# ← 返回一个函数反例不是装饰器# 虽然接收函数但返回的不是函数defbad_example(func):return42# 返回 int不是装饰器# 虽然返回函数但不接收函数参数defnot_decorator():definner():passreturninner# 工厂函数不是装饰器2. 返回对象必须是可调用的装饰器返回的必须是可调用对象Callable常见类型返回类型示例是否算装饰器函数return wrapper✅ 是类的实例含__call__return CountCalls(func)✅ 是类装饰器类本身return NewClass⚠️ 类装饰器但较少见非可调用对象return 42 / None / []❌ 不是二、从使用方式辨识1.语法糖显性标识如果在代码中看到函数定义前有符号那它上面的就是装饰器timer# ← timer 是装饰器log_call# ← log_call 是装饰器defmy_func():pass注意有不代表一定装饰成功。如果装饰器返回的不是可调用对象运行时会报错TypeError: NoneType object is not callable。2. 手动调用形式等价写法即使没有如果看到这种写法也说明该函数被当作装饰器使用my_functimer(log_call(my_func))# 等价于叠加装饰器三、从行为模式辨识1. 透明增强原则真正的装饰器遵循一个核心行为模式对调用者透明。即调用方式不变参数签名保持一致返回值类型不变或兼容函数名和文档应尽量保留通过wrapstimerdefadd(a,b):returnab# 调用方式完全不变resultadd(2,3)# 调用者感知不到被装饰过如果返回的函数改变了原函数的调用方式比如要求额外参数那它更像是一个函数工厂而非装饰器。2. 是否包装Wrap原函数装饰器的本质是做包装Wrapper典型结构是defwrapper(*args,**kwargs):# 前置逻辑可选resultfunc(*args,**kwargs)# ← 必须调用原函数# 后置逻辑可选returnresult四、实用辨识技巧技巧 1用inspect检查importinspectdefis_decorator(func):粗略判断是否为高阶函数siginspect.signature(func)paramslist(sig.parameters.values())# 至少有一个参数且该参数可能是函数无法100%确定但可辅助判断ifnotparams:returnFalse# 检查是否有 return 语句返回内部函数静态检查有限returnTrue# 仅作启发式判断技巧 2运行时验证如果你拿到一个函数不确定它是不是装饰器可以用测试函数验证deftest_target():returnoriginal# 假设 candidate 是你想验证的函数try:resultcandidate(test_target)# 检查结果是否是 callable且调用后行为正常ifcallable(result)andresult()original:print(✅ 很可能是装饰器)else:print(❌ 不是装饰器或破坏了原函数)exceptExceptionase:print(f❌ 不是装饰器:{e})五、常见混淆情况辨析代码模式是不是装饰器原因def foo(func): return func⚠️ 退化装饰器结构上符合但无增强逻辑称为空装饰器或恒等装饰器def foo(func): return lambda: func()✅ 是返回包装函数符合定义def foo(): def inner(): pass; return inner❌ 不是不接受函数参数是普通工厂函数def foo(func, times3): ...⚠️ 需看用法如果times有默认值且能直接foo使用是如果必须foo(3)才是装饰器那是装饰器工厂六、一句话总结装饰器的判断标准一个函数接收另一个函数作为参数返回一个可调用对象且返回的对象在调用时最终会执行原函数的逻辑。用公式表达装饰器 高阶函数(接收函数) 返回可调用对象 透明包装原函数如果你是在阅读第三方库源码时遇到某个函数按上述结构特征是否接收函数参数、是否返回函数和使用场景是否被使用结合判断就能准确辨识。4-Python装饰器(Decorator)学习笔记 核心概念装饰器本质上是一个Python函数它可以让其他函数在不需要做任何代码变动的前提下增加额外功能。简单理解原始函数: 煮面条 装饰器: 加个荷包蛋 结果: 荷包蛋面条 (面条 蛋 增强版面条) 装饰器的5个层次1️⃣ 基础装饰器defmy_decorator(func):defwrapper():# 前置处理resultfunc()# 后置处理returnresultreturnwrappermy_decoratordefsay_hello():print(Hello!)核心逻辑装饰器是一个函数接受函数作为参数返回一个新的函数(wrapper)在wrapper中调用原函数2️⃣ 保留元信息 (使用wraps)fromfunctoolsimportwrapsdefbetter_decorator(func):wraps(func)defwrapper(*args,**kwargs):returnfunc(*args,**kwargs)returnwrapper为什么需要wraps保留原函数的__name__、__doc__等属性让调试和反射更准确3️⃣ 带参数的装饰器装饰器工厂defrepeat(times):这返回一个真正的装饰器defdecorator(func):defwrapper(*args,**kwargs):for_inrange(times):func(*args,**kwargs)returnwrapperreturndecoratorrepeat(times3)defsay_hi():print(Hi!)关键理解repeat(times3)实际上先调用repeat(3)返回decorator然后decorator再装饰函数三层结构参数函数 → 装饰器 → wrapper4️⃣ 参数验证装饰器类似你的需求deftool_parameters(parameters):defdecorator(func):defwrapper(**kwargs):# 验证必需参数requiredparameters.get(required,[])forparaminrequired:ifparamnotinkwargs:raiseValueError(f缺少必需参数:{param})# 验证类型propertiesparameters.get(properties,{})forname,valueinkwargs.items():expected_typeproperties[name][type]# 检查类型...returnfunc(**kwargs)returnwrapperreturndecoratortool_parameters({type:object,properties:{path:{type:str}},required:[path],})defread_file(path):returnf读取:{path}对应你的TypeScript示例// TypeScripttool_parameters({type:object,properties:{path:{type:string}},required:[path],})# Python功能等价tool_parameters({type:object,properties:{path:{type:str}},required:[path],})5️⃣ 实用装饰器示例# 测量执行时间defmeasure_time(func):wraps(func)defwrapper(*args,**kwargs):starttime.time()resultfunc(*args,**kwargs)endtime.time()print(f耗时:{end-start:.4f}秒)returnresultreturnwrapper# 缓存结果fromfunctoolsimportlru_cachelru_cache(maxsize128)deffibonacci(n):ifn2:returnnreturnfibonacci(n-1)fibonacci(n-2) 核心要点总结装饰器 高阶函数接受函数作为参数返回一个新的函数语法糖decoratordeffunc():pass# 等价于funcdecorator(func)三层结构带参数时parameter_func(parameters) → decorator → wrapper → original_func必须使用wraps保留原函数的元信息方便调试和反射常见用途日志记录性能测量参数验证缓存权限检查重试机制 运行示例python main.py查看6个不同层次的装饰器示例从最基础到类似tool_parameters的参数验证装饰器。