函数式编程之装饰器
一. 前言
借用比较经典的两段话,自行理解。
“函数式编程关心数据的映射,命令式编程关心解决问题的步骤”
“什么面向对象,什么函数式,都是看待问题的一种方式,是世界观。面向对象就像把所有的东西都看作独立的个体,它们可以被归类,有自己的状态,可以互相发消息。面向对象编程思维就是设计好一个个对象,然后自己亲手去“摆弄”它们。谁什么时间干什么,安排的明明白白。而函数式则是把世界看成一个整体。就像我们高中学物理的动力学似的,给定一个初始状态,根据牛顿动力学定律,整个体系之后的运动都是确定的。是一个个具体的运动规则应用在整个体系之上,整个体系被运动规则驱动,做着完全可预测的工作。所以函数式当然没有什么变量,没有什么副作用,因为我们是物理学家,我们在用规则刻画整个世界。我们没有什么对象,没有什么消息,有的只是【一切】——>【规则】——>【[新的一切】。”
二. 装饰器
装饰器是函数式编程的表现形式,下面通过代码体验一下装饰器。
装饰器——在不更改原函数的代码的前提下给函数增加新的功能,特殊之处在于它的返回值也是一个函数!
三. 闭包示例代码
def fun1(name1): def fun2(name2): # 4.hello传到这儿了,函数这东西不调用就不执行 print(name1 + name2) print('2') # 1.上面函数没调用就不执行,直接从这儿开始 return fun2 # 2写的是函数名,返回地址 a = fun1('tom') a('hello') # 3指向fun1的返回值即fun2('hello') a('hi') # 5同上 # 通过闭包更改外部函数值用nonlocal arg def func_out(num1): def func_inner(num2): nonlocal num1 # 可以改变这个值 num1 = num1 + num2 print("num1:", num1) print(num1) func_inner(1) # 之所以这样,因为得跑一遍才能改呀,直接打印num1,数据流没跑到那儿肯定没修改。 print(num1) return func_inner f = func_out(1) f(2) # 装饰器基础结构 def check(fn): def inner(): print("请先登录....") fn() # 5指向comment() return inner # 1指向下面的调用者comment def comment(): print("发表评论") # 6 comment = check(comment) # 2 comment装的是inner函数的地址。可改成@check即装饰器,放在被装饰方法comment()的上方。 comment() # 3指向inner()# 通用装饰器
四. 普通装饰器1
import time # 普通的装饰器 def show_time(func): # 第一个参数永远是目标函数名(不干扰的函数) # 这里可以写多层 def wrapper(*args, **kwargs): # 多个参数没关系的 star_time = time.time() my_func = func(*args, **kwargs) # 目标函数可以调整位置以改变执行顺序 end_time = time.time() - star_time # 统计函数运行时间的功能 print("总用时 ", end_time) return my_func # 指向函数,这里可以不用return。中间直接执行函数不用赋值给变量 return wrapper # 指向内层函数名 @show_time def say_hello(username): time.sleep(0.33) print("hello!", username) say_hello("chrisiven")
五. 普通装饰器2
# (包含了不定长参数、带返回值函数;多debug,先执行两个装饰器,跑没头了,给调用它的人) def logging(fn): def inner(*args, **kwargs): print("--正在努力计算--") result = fn(*args, **kwargs) # 藏的有点深啊,所以下面不必再写sum_num()这个指向inner的方法。 return result return inner @logging def sum_num(*args, **kwargs): result = 0 for value in args: result += value print(result) for value in kwargs.values(): result += value print(result) return result @logging def subtraction(a, b): result = a - b print(result) result = sum_num(1, 2, a=10) print(result) subtraction(4, 2) check=Check(print) #也可以改input,拓展:上面args[0]('注册')表示print('注册'),间接表明一切皆对象。 check()
六. 多装饰器
# 多装饰器 def make_div(func): """对被装饰的函数的返回值 div标签""" def inner(*args, **kwargs): return "<div>" + func() + "</div>" return inner def make_p(func): """对被装饰的函数的返回值 p标签""" def inner(*args, **kwargs): return "<p>" + func() + "</p>" return inner # 装饰过程: 1 content = make_p(content) 2 content = make_div(content) # content = make_div(make_p(content)) @make_div @make_p def content(): return "你好哈哈" result = content() print(result)
七. 带参装饰器
def show_times(logger): # 你传递的数据 def wrapper(func): # 你的函数 def exec(*args, **kwargs): # 目标函数参数,如果有的话 print(args, kwargs) print("已经被{}控制".format(logger)) my_func = func(*args, **kwargs) return my_func return exec return wrapper @show_times("logger") # 在定义你的主函数时进行传递。 def say_hello(username): print("hello,{}".format(username)) say_hello("chrisiven")
八. 类装饰器
import time # 类装饰器 class Check(object): def __init__(self, fn): # 初始化操作在此完成 self.__fn = fn # 实现__call__方法,表示对象是一个可调用对象,可以像调用函数一样进行调用。 def __call__(self, *args, **kwargs): # 添加装饰功能 print("请先登陆...") self.__fn('sdf') @Check def comment(): print("发表评论") comment()
九. 装饰器传参
# 装饰器传参 # 需要多余两层的嵌套,多少层没有关系,重点关注装饰的那一层是谁,在这里装饰层是warpper。a,b,c用来调试用 def deprecated(new_fun_name): a = new_fun_name # 1 print('a:', a) def warpper(fun): # 2, 4 b = fun.__name__ # 5 print('b:', b) def inner(*args): # 7 c = args # 12 print('c:', c) return fun(*args) # 13, 16 return inner # 8 return warpper # 3 @deprecated('add') # 4,9, 14 def add_fun(x, y): return x + y # 10, 6, 15 if __name__ == "__main__": # 10 res = add_fun(2, 2) # 5, 11, 17 print(res) # 18-over
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 提示词工程——AI应用必不可少的技术
· Open-Sora 2.0 重磅开源!
· 周边上新:园子的第一款马克杯温暖上架