day6 装饰器总结
装饰器:开放封闭原则,为一个函数加上新的功能,不改变原函数,不改变调用方式
def fun2(wtf):
def fun3():
print('i am pythoner!!! ')
wtf()
return fun3 @fun2
def fun1():
print('this is fun1')
fun1() 输出:
i am pythoner!!!
this is fun1
def fun2(wtf):
def fun3(*args, **kwargs):
print('i am pythoner!!! ')
wtf(*args, **kwargs)
return fun3 #这里不是fun3()是因为:return作用在于函数赋值,即让fun3指向fun1的函数内存地址 @fun2 # @fun2 当于fun1 = fun2(fun1) ,把下面的函数传递到装饰器函数里面,相当于 fun1 = fun2(fun1) = fun3(用return令fun1=fun3), 后面再执行fun1() , 相当于执行fun3()
def fun1(arg, arg2):
print('this is fun1: %s %d' % (arg, arg2))
fun1('tom', 55) #注意此处fun1()调用的实际是fun3(),而不是原来的fun1()了
注意:只要函数应用装饰器,函数就被重新定义,重新定义为:装饰器的内层函数
def runtime(func):
def warpper():
start_time = time.time()
func()
end_time = time.time()
print 'run time is %s' % (end_time-start_time)
return warpper @runtime
def test1():
time.sleep(3)
print 'in the test1' test1() 带参数的装饰器举例:
def outer(func):
def inner(a, b):
print('heihei')
r = func(a, b) #func即index函数,即inner函数
return r
return inner @outer # index = outer(index) = inner
def index(a1, a2):
print('----------')
return a1 + a2 print(index(1, 2)) 输出:
heihei
----------
3 @outer 作用
1. 执行outer函数,将index作为参数传递
2. 将outer的返回值,重新赋值给index
3. 执行index函数时不再是原来的index函数,而是执行装饰器中的inner函数(由装饰器中的return赋值使index=inner)
带N个参数的装饰器:
应用场景:
当一个装饰器装饰多个函数时,而这些函数的参数个数都不相同时。
原理:
#原理:
def f1(*args, **kwargs):
print(args)
print(kwargs) f1(1, 2, 3, 4, M1='')
输出:
(1, 2, 3, 4)
{'M1': ''} dic = {'a': 2, 'b': 23333}
tup = (1, 2, 3)
f1(*tup, **dic) 输出:
(1, 2, 3)
{'a': 2, 'b': 23333}
举例:
def outer(func):
def inner(*args, **kwargs):
print('into inner')
print('the arg is :', *args, **kwargs)
r = func(*args, **kwargs)
return r
return inner @outer # index = outer(index) = inner
def index(a1, a2):
print('----------')
return a1 + a2 print(index(1, 2)) @outer # f1 = outer(f1) = inner
def f1(a1):
print('++++++++++++++++++++++++++')
return a1 * a1
print(f1(2)) #输出:
into inner
the arg is : 1 2
----------
3
into inner
the arg is : 2
++++++++++++++++++++++++++
4
多个装饰器装饰同一个函数:
def outer(func): #func等同于outer2中的inner2
def inner(*args, **kwargs):
print('first decorate-------------')
print('the arg is :', *args, **kwargs)
r = func(*args, **kwargs) #func等于outer2中的inner2,r值为inner2中的 return r
print('first decorate-------------')
return r # r的值最终返回给index
return inner def outer2(func): #func等于index
def inner2(*args, **kwargs): #inner2等同于于outer2+被outer2装饰的index函数
print('second decorate-----------')
r = func(*args, **kwargs) #func等于index,r值为index的return a1 + a2
print('second decorate------------')
return r #r为inner2的返回值,返回给outer中的func函数
return inner2 @outer # outer(inner2) = inner, 作用:将outer2装饰的index,即inner2当作参数传递到第一个装饰器中outer中
@outer2 # index = outer2(index) = inner2
def index(a1, a2):
print('ori func----------')
return a1 + a2 print(index(1, 2)) 输出:
first decorate-------------
the arg is : 1 2
second decorate-----------
ori func----------
second decorate------------
first decorate-------------
3 执行顺序说明:
当运行index(1, 2)时,
1.执行第一个装饰器outer中的inner函数
2.由1步中的inner函数中的func函数,执行outer2中的inner2函数
3.执行outer2中inner2中的func函数,即执行最初需要装饰的index函数
4.index的返回值返回给它的调用者,即inner2中的func函数
5。inner2的返回值返回给它的调用者,即inner中的func函数
6.将r返回给index函数
https://segmentfault.com/a/1190000007837364 def decorator_b(func): print ('Get in decorator_b') #
def inner_b(*args, **kwargs):
print ('Get in inner_b') #
return func(*args, **kwargs)
return inner_b def decorator_a(func): print ('Get in decorator_a') #
def inner_a(*args, **kwargs):
print ('Get in inner_a') #
return func(*args, **kwargs)
return inner_a @decorator_b
@decorator_a
def f(x):
print ('Get in f') #
return x * 2 f # 分步骤来,这里很重要。这里会先后打印出Get in decorator_a 和Get in decorator_b 1、输入函数名f,意味着将函数f作为参数,传入装饰器a和b。 1.5、但是并未调用函数f(x),也就是f(x)函数并不会执行,因为没有传入参数。重点也就在这,函数和函数调用是不一样的。 2、f首先传入装饰器a,也就是装饰器a函数获得参数被调用,那么就执行打印,并同时返回函数inner_a。 2.5、当然,此时函数inner_a也没有被调用。因为同样没有参数传入。 3、inner_a传入装饰器b,也就是装饰器b函数获得参数被调用,那么也执行打印,并同时返回函数inner_b。 4、现在就是返回函数inner_b>inner_a>f
f(1) # 然后输入这段代码,会先后打印出Get in inner_b和Get in inner_a,以及Get in f 5、此时函数f获得参数1,即函数被调用,由于上面步骤4中最后返回函数是inner_b,那么最先调用最外层的函数,print先行,也就是先打印Get in inner_b,再返回inner_a函数; 6、进而调用inner_a函数,print先行,也就是先打印Get in inner_a,再返回f(1)函数; 7、最后调用f(1)函数,print先行,也就是先打印Get in f,再返回2。 8、这样顺序就理顺了,哈哈,我这么理解的。 装饰器由下到上依次立马执行,之后我们调用的f已经是被装饰器执行了之后的f了,此时是由上到下返回去依次调用。整个过程有点像先上楼梯(装饰过程),再下楼梯(调用函数)
在实际应用的场景中,当我们采用上面的方式写了两个装饰方法比如先验证有没有登录 @login_required
, 再验证权限够不够时 @permision_allowed
时,我们采用下面的顺序来装饰函数:
@login_required
@permision_allowed
def f()
# Do something
return
小结:执行装饰器函数的顺序是由下到上(由内到外),调用f(被装饰的函数)是由上到下
对于装饰器来说,在这里程序从上到下执行,开始记录装饰器1-3,然后读到了函数的时候,装饰器开始装饰,把函数的引用传入装饰器中,从装饰器3开始往上装饰,所以这时候开始执行装饰器3的初始化,并把装饰完的函数当做一个新的函数,再次把新的引用传入到装饰器2,接着装饰器2进行初始化,再次把新的函数的引用传入到装饰器1进行装饰,这时候装饰器1的初始化开始,并开始执行,从而接下来的执行顺序为1-3执行装饰的内容,最后再执行本来的函数,达到一个对原有函数增加功能和特性的要求。
装饰器:从程序开始的顺序,从上到下读取----》从下到上装饰----》从上到下执行
https://www.cnblogs.com/wf-skylark/p/9310448.html
def a(func):
print 'Get in decorator_a'
def inner_a(*args, **kwargs):
print 'Get in inner_a'
print "in a, args ", args
print "in a, kwargs ", kwargs
kwargs.update({"params": ""})
return func(*args, **kwargs)
return inner_a def b(func):
print 'Get in decorator_b'
def inner_b(*args, **kwargs):
print 'Get in inner_b'
print "in b, args ", args
print "in b, kwargs ", kwargs
return func(*args, **kwargs)
return inner_b @b
@a
def f(x, params):
print 'Get in f'
print "params: ", params
return x * 2 f(*(1, )) # 执行步骤: 执行f(*(1, )),调用装饰器a(即执行a函数:a(f)), a返回一个inner_a (inner_a = a(f)),执行f(*(1, ))等价于inner_a(*(1, ))
# 调用装饰器b,并把inner_a(*(1, ))传入b中,inner_a = inner_b ,inner_a(*(1, ))即执行inner_b(*(1, )),
# inner_b执行后return并执行inner_a(*(1, )),最后在inner_a中return并执行f(*(1, )) #结果:
Get in decorator_a
Get in decorator_b
Get in inner_b
in b, args (1,)
in b, kwargs {}
Get in inner_a
in a, args (1,)
in a, kwargs {}
Get in f
params: 1234
示例:
def decorator_a(func):
# print func.func_name
print 'in a'
def inner_a(*args, **kwargs):
print 'Get in inner_a'
return func(*args, **kwargs)
return inner_a def decorator_b(func):
# print func.func_name
print 'in b'
def inner_b(*args, **kwargs):
print 'Get in inner_b'
return func(*args, **kwargs)
return inner_b @decorator_b # 相当于decorator_b包裹了decorator_a,decorator_a包裹了f(x) ,decorator_a包裹了f(x)等同于 inner_a,同理,decorator_b包裹的函数等于inner_b
@decorator_a
def f(x):
print 'Get in f'
return x * 2 print f(1) # 相当于执行f(1) = decorator_b(decorator_a(f(1))) = inner_b(1)
# 调用顺序:有内到外,先由f(1)传入装饰器decorator_a,打印“in a”, 返回inner_a,
# 执行顺序,先执行decorator_b中的inner_b函数,再执行decorator_a中的inner_a。 https://zhuanlan.zhihu.com/p/26889350
自身带参数的装饰器
例1:
user_list=[
{'name':'alex','passwd':''},
{'name':'linhaifeng','passwd':''},
{'name':'wupeiqi','passwd':''},
{'name':'yuanhao','passwd':''},
]
current_dic={'username':None,'login':False} def auth(auth_type='filedb'):
def auth_func(func):
def wrapper(*args,**kwargs):
print('认证类型是',auth_type)
if auth_type == 'filedb':
if current_dic['username'] and current_dic['login']:
res = func(*args, **kwargs)
return res
username=input('用户名:').strip()
passwd=input('密码:').strip()
for user_dic in user_list:
if username == user_dic['name'] and passwd == user_dic['passwd']:
current_dic['username']=username
current_dic['login']=True
res = func(*args, **kwargs)
return res
else:
print('用户名或者密码错误')
elif auth_type == 'ldap':
print('鬼才特么会玩')
res = func(*args, **kwargs)
return res
else:
print('鬼才知道你用的什么认证方式')
res = func(*args, **kwargs)
return res return wrapper
return auth_func @auth(auth_type='filedb') #auth_func=auth(auth_type='filedb')-->@auth_func 附加了一个auth_type --->index=auth_func(index)
def index():
print('欢迎来到京东主页') @auth(auth_type='ldap')
def home(name):
print('欢迎回家%s' %name)
#
@auth(auth_type='sssssss')
def shopping_car(name):
print('%s的购物车里有[%s,%s,%s]' %(name,'奶茶','妹妹','娃娃')) # print('before-->',current_dic)
# index()
# print('after--->',current_dic)
# home('产品经理')
shopping_car('产品经理')
例2:
# !/usr/bin/env python
# coding:utf-8 def before(request, kargs):
print('before') def after(request, kargs):
print('after') def Filter(before_func, after_func):
def outer(main_func):
def wrapper(request, kargs): before_result = before_func(request, kargs)
if before_result:
return before_result main_result = main_func(request, kargs)
if main_result:
return main_result after_result = after_func(request, kargs)
if after_result:
return after_result return wrapper return outer # outer = Filter(before, after) ---> 相当于@outer附带参数(before, after) 相当于执行 ==> index = outer(index)
@Filter(before, after)
def index(request, kargs):
print('index') index(1,2) # 带参数的装饰器:利用装饰器的最外层函数传参
装饰器------------自己的理解(持续更新)
def fun2(wtf):
def fun3():
print('i am pythoner!!! ')
wtf()
return fun3 @fun2
def fun1():
print('this is fun1')
fun1() 输出:
i am pythoner!!!
this is fun1 fun2只是个桥梁:
0.把要装饰的函数接收进来,嵌套进包含新功能的函数(这个函数同时包含原函数功能)
1.让fun1和fun3内存地址相同 目的:装饰后在fun1()执行前后再执行一些其他的动作 def outer(func): #
def inner(a, b): # 2 a:1 b:2
print('heihei') #
r = func(a, b) # func即index函数,即inner函数 # 4
return r # 如果index有返回值,这里要加上return返回index的返回值 # 7
return inner # 作用:让index和inner内存地址相同 @outer # index = outer(index) = inner
def index(a1, a2):
print('----------') #
return a1 + a2 # print(index(1, 2)) # 偷梁换柱,相当于直接执行包含原函数功能的函数inner(1, 2) # 1
def write_log(func):
def wrapper(a, b):
print 'log --------------'
return func(a, b) return wrapper # @write_log
def bar(a,b):
return a + b print write_log(bar)(1, 3)
# write_log(bar) 等于 wrapper
# write_log(bar)(1, 3) 等于 wrapper(1, 3) #输出:
log --------------
4
def public(f):
""""
Use a decorator to avoid retyping function/class names.
Based on an idea by Duncan Booth:
http://groups.google.com/group/comp.lang.python/msg/11cbb03e09611b8a
Improved via a suggestion by Dave Angel:
http://groups.google.com/group/comp.lang.python/msg/3d400fb22d8a42e1
"""
# all = sys.modules[f.__module__].__dict__.setdefault('__all__', [])
# if f.__name__ not in all: # Prevent duplicates if run from an IDE.
# all.append(f.__name__)
print('new feature ---')
# return '1123'
return f # public(public) # Emulate decorating ourself # @public # public(str_fsize)(10000)
def str_fsize(sz):
"""
Formats file size as string (i.e., 1.2 Mb)
"""
if sz < 1024:
return '%.1f bytes' % sz
sz /= 1024.0
if sz < 1024:
return '%.1f KB' % sz
sz /= 1024.0
if sz < 1024:
return '%.1f MB' % sz
sz /= 1024.0
if sz < 1024:
return '%.1f GB' % sz
sz /= 1024.0
return '%.1f TB' % sz a = public(str_fsize)(1000000)
print(a) # a = str_fsize(1000000)
# print(a)
新的理解:
如果只在函数执行前加某些功能,装饰器可以简化:
import time def decorator(sss):
print("begin to run xxx") return sss @decorator
def fun(a):
time.sleep(1)
print(a)
fun(3) # 相当于在执行decorator(fun)(3) => return fun => fun(3) (扒皮,脱壳)
# decorator(fun)(3) # 注意:decorator(fun)和fun完全等价,内存地址相同
# begin to run xxx #
def public(f):
""""
Use a decorator to avoid retyping function/class names.
Based on an idea by Duncan Booth:
http://groups.google.com/group/comp.lang.python/msg/11cbb03e09611b8a
Improved via a suggestion by Dave Angel:
http://groups.google.com/group/comp.lang.python/msg/3d400fb22d8a42e1
"""
# all = sys.modules[f.__module__].__dict__.setdefault('__all__', [])
# if f.__name__ not in all: # Prevent duplicates if run from an IDE.
# all.append(f.__name__)
def inner(a):
print('new feature1 ---') # 要添加的新功能
val = f(a)
print('new feature2 ---') # 要添加的新功能
return val # 原函数有返回值这里必须返回
# return '1123'
return inner # public(public) # Emulate decorating ourself @public # public(str_fsize)(10000)
def str_fsize(sz):
"""
Formats file size as string (i.e., 1.2 Mb)
"""
if sz < 1024:
return '%.1f bytes' % sz
sz /= 1024.0
if sz < 1024:
return '%.1f KB' % sz
sz /= 1024.0
if sz < 1024:
return '%.1f MB' % sz
sz /= 1024.0
if sz < 1024:
return '%.1f GB' % sz
sz /= 1024.0
return '%.1f TB' % sz a = str_fsize(1000000000000000)
print(a)
原函数执行前后都加功能
装饰器含参:
import time def decorator(sss):
print('aaa', sss)
def outer(aaa):
print('aaa', sss)
def inner(s):
print("begin to run xxx")
aaa(s)
print("run completed")
return inner
return outer @decorator(123)
def fun(a):
time.sleep(1)
print(a) fun(3) #输出:
aaa 123
aaa 123
begin to run xxx
3
run completed
day6 装饰器总结的更多相关文章
- python day6 装饰器补充,正则表达式
目录 python day 6 1. 装饰器decorator 2. 正则表达式re 2.1 正则表达式概述 2.2 re模块常用方法 python day 6 2019/10/09 学习资料来自老男 ...
- python 二——函数、装饰器、生成器、面向对象编程(初级)
本节内容 1.函数 2.装饰器 3.生成器 4.类 一.函数 函数式:将某功能代码封装到函数中,日后便无需重复编写,仅调用函数即可 面向对象:对函数进行分类和封装,让开发“更快更好更强...” 函数式 ...
- Python高手之路【四】python函数装饰器
def outer(func): def inner(): print('hello') print('hello') print('hello') r = func() print('end') p ...
- python装饰器
今天看了装饰器的一些内容,感觉@修饰符还是挺抽象的. 装饰器就是在不用改变函数实现的情况下,附加的实现一些功能,比如打印日志信息等.需要主意的是装饰器本质是一个高阶函数,她可以返回一个函数. 装饰器需 ...
- Python(四)装饰器、迭代器&生成器、re正则表达式、字符串格式化
本章内容: 装饰器 迭代器 & 生成器 re 正则表达式 字符串格式化 装饰器 装饰器是一个很著名的设计模式,经常被用于有切面需求的场景,较为经典的有插入日志.性能测试.事务处理等.装饰器是解 ...
- [原创]django+ldap实现单点登录(装饰器和缓存)
前言 参考本系列之前的文章,我们已经搭建了ldap并且可以通过django来操作ldap了,剩下的就是下游系统的接入了,现在的应用场景,我是分了2个层次,第一层次是统一认证,保证各个系统通过ldap来 ...
- PHP 装饰器模式
装饰器模式:是在不必改变原类文件和使用继承的情况下,动态地扩展一个对象的功能. [装饰器模式中主要角色] 抽象组件角色(Component):定义一个对象接口,以规范准备接受附加责任的对象,即可以给这 ...
- python cookbook 学习系列(一) python中的装饰器
简介 装饰器本质上是一个Python函数,它可以让其他函数在不需要做任何代码变动的前提下增加额外功能,装饰器的返回值也是一个函数对象.它经常用于有切面需求的场景,比如:插入日志.性能测试.事务处理.缓 ...
- python基础补漏-05-生成器和装饰器
[1]生成器 很难用简单的语言描述生成器. 生成器:从字面上来理解,就是以某种规则为基础,不断的生成数据的工具 生成器函数: 在函数中如果出现了yield关键字,那么该函数就不再是普通函数,而是生成器 ...
随机推荐
- Docker Push 镜像到公共仓库
首选需要在https://hub.docker.com/上注册用户. 1.登录docker账号主要命令:docker login sudo docker login 2.推送镜像主要命令:docker ...
- C++井字棋游戏,DOS界面版
据说有一个能保证不败的算法.明天看看先再写个PVC版的. 正题.今天无聊写了个井字棋游戏,顺便逐渐让自己习惯良好的代码风格,放上来给新手学习学习. jzq2.cpp /* N字棋游戏PVP版,DOS版 ...
- MapReduce中的排序(附代码)
在直接学习hadoop的排序之前还要了解一些基本知识. Hadoop的序列化和比较接口 Hadoop的序列化格式:Writable Writable是Hadoop自己的序列化格式,还要一个子接口是Wr ...
- iOS系列译文:自定义Collection View布局
原文出处: Ole Begemann 译文出处: 黄爱武(@answer-huang).欢迎加入技术翻译小组. UICollectionView在iOS6中第一次被介绍,也是UIKit视图类中的一 ...
- Ajax跨域请求,无法传递及接收cookie信息解决方案
最近的项目中涉及到了应用ajax请求后台系统登录,身份认证失败,经过不断的调试终于找到解决方案. 应用场景: 项目测试环境:前端应用HTML,js,jQuery ajax请求,部署在Apache服务器 ...
- Unity3D研究院之在开始学习拓展编辑器
Unity拥有非常丰富的拓展编辑器接口,如果是在网上下载过别人写的插件,你会发现为什么它的监测面板视图和普通的不一样?其实是他通过代码自己绘制的监测面板,这篇博文MOMO带大家来学习编辑器.如下图所示 ...
- 【JavaScript】BOM和DOM
在第一篇JavaScript视频总结博客中.是对JavaScript做了一个宏观的认识.当中,不知道大家可否还记得.JavaScript的核心部分包含哪些? JavaScript的核心部分主要包含三个 ...
- maven;tomcat配置
[说明]今天呀,上午刚刚打算写javaweb项目,服务器就出现了问题,就花了点时间搞定了:下午听老大说了任务的大致内容和意义,收获颇多:晚上去服务器上部署了maven,听说可以实现热部署 一:今天完成 ...
- 【BZOJ4070】[Apio2015]雅加达的摩天楼 set+最短路
[BZOJ4070][Apio2015]雅加达的摩天楼 Description 印尼首都雅加达市有 N 座摩天楼,它们排列成一条直线,我们从左到右依次将它们编号为 0 到 N−1.除了这 N 座摩天楼 ...
- vue Element UI 导航高亮
1. activeIndex 为默认高亮值,根据改变activeIndex的值来改变高亮的值 当页面改变的时候获取当前的路由地址,截取第一个 / 后面的值,就是当前的高亮值了 为什么要截取呢? 因为点 ...