装饰器 ╰+攻爆jí腚メ 2022-06-07 11:58 226阅读 0赞 ### 装饰器 ### 装饰模式有很多经典的使用场景,例如插入日志、性能测试、事务处理等等,有了装饰器,就可以提取大量函数中与本身功能无关的类似代码,从而达到代码重用的目的。 #### 装饰器引入 #### 下面就简单举个例子: 一天,A程序员接到一个登入的需求,写了一个方法。 def login(): print('登入') login() # 输出 登入 突然,产品经理想加入一个登入事件。于是A程序员对方法进行了修改。 def login(): print('事件记录') print('登入') login() # 输出 事件记录 登入 然后,A的老大看到了说,你这样违反了开闭原则,好好思考一下如何改进。后面A就改进,通过闭包的方式,定义了一个event函数。 # 定义一个event函数,记录事件 def event(func): def inner(): print('事件记录') func() return inner def login(): print('登入') login = event(login) # 这个代码意思是,把定义的login函数作为变量传递给event作为参数。event函数的返回值在赋值login变量 login() # 调用login变量的方法 # 输出 事件记录 登入 这里有个比较难理解的地方就是,def定义了一个login函数,实际上它是一个login变量指向def定义的login函数的地址值。 eg: def login(): print('登入') print(login) # <function login at 0x000001D8D0543E18> a = login # 将login函数的内存地址指向给a变量 a() # 调用a函数,实际上调用的是a指向的地址值的方法 # 输出 登入 这个例子就说明login是一个变量,这个变量指向login函数地址值。 理解了这个例子,那么`login = event(login)`就比较好解释了。 login = event(login) 等号左边的login是event()的返回值,是经过inner变量赋值,inner变量指向的是inner函数的地址值。 等号右边的login变量是指向login函数的地址值。作为参数传递给event函数。实际上是在inner函数中调用。 login() 调用login函数,因为login变量经过inner变量赋值,所以这时的login变量指向的是inner函数的地址值。 也就是说,login()调用,实际上调用的是inner函数,inner函数执行的顺序是: print('事件记录') func() func参数是由event函数传入,也就是login = event(login)式子等号右边的login,这个login变量指向的是def定义login()。 所以输出的结果是: 事件记录 登入 -------------------- #### 装饰器语法糖 #### 在Python中,可以使用`@`语法糖来精简装饰器的代码: 使用了`@`语法糖后,我们就不需要额外代码来给`login`重新赋值了。 eg: def event(func): def inner(): print('事件记录') func() return inner @event # 实际上做了 login = event(login)操作 def login(): print('登入') login() # 输出 事件记录 登入 这里`login()`的`@event`,其实本质就是`login = event(login)`,`@`做了一步赋值操作。当认清了这一点后,后面看带参数的装饰器就简单了。 #### 被装饰的函数带参数 #### 我们只带login()作为登入函数,实际上是有用户名和密码的,这个时候login()需要2个参数,那么怎么处理呢。 eg: def event(func): def inner(username, password): print('事件记录') func(username, password) return inner @event def login(username, password): print('username is %s password is %s,登入成功' %(username,password)) login('amy','123456') # 输出 事件记录 username is amy password is 123456 如果这时候需要加上一个注册的方法,注册需要3个参数,怎么使用呢?这个时候需要使用可变参数`*args, **kwargs`。 eg: def event(func): def inner(*args, **kwargs): print('事件记录') func(*args, **kwargs) return inner @event def login(username, password): print('username is %s , password is %s,登入成功' % (username, password)) @event def register(username, password, email): print('username is %s , password is %s , email is %s,注册成功' % (username, password, email)) login('amy','123456') # 输出 事件记录 username is amy , password is 123456 , 登入成功 register('anne', '654321' , 'abc@126.com') # 输出 事件记录 username is amy , password is 123456 , email is abc@126.com , 注册成功 #### 被修饰的函数带返回值 #### 现在登入和注册成功后,需要有返回值,那么怎么处理,请看下面例子: def event(func): def inner(*args, **kwargs): print('事件记录') ret = func(*args, **kwargs) return ret return inner @event def login(username, password): print('username is %s , password is %s' % (username, password)) return '登入成功' @event def register(username, password, email): print('username is %s , password is %s , email is %s' % (username, password, email)) return '注册成功' ret = login('amy','123456') print(ret) # 输出 登入成功 ret = register('anne', '654321' , 'abc@126.com') print(ret) # 输出 注册成功 如果函数没有返回值,怎么处理,函数没有返回值,其实返回的是None。上面的装饰器是比较通用的装饰器。 #### 带参数的装饰器 #### eg: def event(debug=True): if (debug): def deco(func): def inner(*args, **kwargs): print('事件记录') return func(*args, **kwargs) return inner else: def deco(func): return func return deco @event() # 使用默认参数 def login(username, password): print('username is %s , password is %s' % (username, password)) return '登入成功' @event(debug=False) # debug参数设置成False,也可以直接写False def register(username, password, email): print('username is %s , password is %s , email is %s' % (username, password, email)) return '注册成功' login('amy', '123456') # 输出 事件记录 username is amy , password is 123456 register('anne', '654321', 'abc@126.com') # 输出 username is anne , password is 654321 , email is abc@126.com `@event`加上参数,目的是可以灵活的控制函数的输出,如是否打开调试信息等。 如果`@event`加上参数,在login()函数定义之前就开始执行。我们可以看一下装饰器的执行顺序。 eg: def event(debug=True): print('event函数调用') if (debug): def deco(func): print('deco函数调用') def inner(*args, **kwargs): print('inner函数调用') # print('事件记录') return func(*args, **kwargs) return inner else: def deco(func): print('deco函数调用') return func return deco @event() def login(username, password): print('login函数调用') # print('username is %s , password is %s' % (username, password)) return '登入成功' # 在未调用函数时,运行,打印输出: event函数调用 deco函数调用 login() # 调用函数后,运行,输出: event函数调用 deco函数调用 inner函数调用 login函数调用 也就是说,定义的event方法和deco方法在未调用时Python解释器就已经开始执行了。 执行步骤: 1.定义event函数 2.调用event函数,执行打印event函数调用语句,返回deco函数的引用 3.使用@event,执行打印deco函数调用语句,返回inner函数的引用 4.使用func进行装饰 5.调用login函数 6.执行inner函数调用语句 7.执行login函数调用语句
相关 装饰器 装饰器 定义: 用来装饰的工具 在不改变源代码及调用方式的基础上额外增加新的功能 开放封闭原则: 扩展是开放的(增加新功能) 修改源码是封闭的(修改已经实现 柔光的暖阳◎/ 2023年10月10日 10:16/ 0 赞/ 46 阅读
相关 装饰器 [https://www.cnblogs.com/cicaday/p/python-decorator.html][https_www.cnblogs.com_cicaday_ ╰半橙微兮°/ 2023年01月06日 01:24/ 0 赞/ 127 阅读
相关 【python】闭包和装饰器、通用装饰器、多个装饰器、带参装饰器、类装饰器 1、闭包 概念: 把使用了外部函数变量的内部函数称为闭包 构成闭包的三个条件: 在函数嵌套的基础上(在外部函数内定义一个内部函数) 内部函数使用外部函数变 - 日理万妓/ 2022年11月28日 13:44/ 0 赞/ 227 阅读
相关 装饰器 装饰器 装饰模式有很多经典的使用场景,例如插入日志、性能测试、事务处理等等,有了装饰器,就可以提取大量函数中与本身功能无关的类似代码,从而达到代码重用的目的。 装饰器 ╰+攻爆jí腚メ/ 2022年06月07日 11:58/ 0 赞/ 227 阅读
相关 装饰器 以前你有没有这样一段经历:很久之前你写过一个函数,现在你突然有了个想法就是你想看看,以前那个函数在你数据集上的运行时间是多少,这时候你可以修改之前代码为它加上计时的功能,但是这 港控/mmm°/ 2022年05月28日 13:27/ 0 赞/ 226 阅读
相关 装饰器 装饰器 如果我们要增强函数的功能,但又不希望修改`原`函数的定义,这种在代码运行期间动态增加功能的方式,称之为“装饰器”(Decorator); 本质上,de 墨蓝/ 2021年12月14日 14:17/ 0 赞/ 247 阅读
相关 装饰器 目录 普通装饰器 带参数的装饰器 多个装饰器装饰一个函数 装饰器的修复技术 装饰器 :在不改变原函数的代号和调用方法的基础上, 给原函数额外增加功能 女爷i/ 2021年10月29日 16:26/ 0 赞/ 362 阅读
相关 装饰器 装饰器的固定模式 def warpper(f): def inner(args,kwargs): print("WDNMD") 我就是我/ 2021年10月29日 07:12/ 0 赞/ 481 阅读
相关 装饰器 定义: 器字代表函数,装饰器本质是函数;装饰:装饰其他函数,就是为其他函数添加附加功能 原则: 1.不能修改被装饰函数的源代码(在不修改被装饰函数源代码的情况下为 心已赠人/ 2021年09月20日 12:00/ 0 赞/ 371 阅读
还没有评论,来说两句吧...