金沙国际官网Python基础(七) python自带的三个装饰器
说到装饰器,就不得不说python自带的三个装饰器:
Python 基础 装饰器,python基础装饰器
今天把学过的装饰器的知识进行回顾一下,说到装饰器,第一反应就是这个东西呢就是用来装逼的,为啥这样说呢,是应为没有这个东西照样可以干活,大部分工作都是可以做的,不管咋样还是把学过的装逼器梳理一下吧。
一、装饰器是个什么鬼?
装饰的意思呢,就是修饰,装点的意思可以给别的函数添加新的功能,器呢就是函数的意思,so
装饰器即是为别的函数添加新的功能的函数。
二、作为一个装饰器,他、它有什么样的规则呢?
1.不修改被装饰函数的源代码(开放封闭原则)
2.为被装饰函数添加新功能后,不修改被修饰函数的调用方式
三、如何实现一个装饰器呢?
要实现一个可以使用的装饰器就需要满足:装饰器=高阶函数+函数嵌套+闭包
四、高阶函数
上节介绍完了什么是高阶函数,只要满足:1.函数可以接受函数名当参数进行传递
2.函数的返回值可以返回一个函数名
只要能够满足上面的任何一条就认为构成的这个函数是高阶函数
高阶函数的例子:
def foo():
print('我的函数名作为参数传给高阶函数')
def gao_jie1(func):
print('我就是高阶函数1,我接收的参数名是%s' %func)
func()
def gao_jie2(func):
print('我就是高阶函数2,我的返回值是%s' %func)
return func
gao_jie1(foo)
gao_jie2(foo)
输出的结果是:
我就是高阶函数1,我接收的参数名是<function foo at 0x006896A8>
我的函数名作为参数传给高阶函数
我就是高阶函数2,我的返回值是<function foo at 0x006896A8>
#高阶函数应用1:把函数当做参数传给高阶函数
import time
def foo():
print('from the foo')
def timmer(func):
start_time=time.time()
func()
stop_time=time.time()
print('函数%s 运行时间是%s' %(func,stop_time-start_time))
timmer(foo)
#总结:我们确实为函数foo增加了foo运行时间的功能,但是foo原来的执行方式是foo(),现在我们需要调用高阶函数timmer(foo),改变了函数的调用方式
把函数当做参数传给高阶函数
#高阶函数应用2:把函数名当做参数传给高阶函数,高阶函数直接返回函数名
import time
def foo():
print('from the foo')
def timmer(func):
start_time=time.time()
return func
stop_time=time.time()
print('函数%s 运行时间是%s' %(func,stop_time-start_time))
foo=timmer(foo)
foo()
#总结:我们确实没有改变foo的调用方式,但是我们也没有为foo增加任何新功能
函数返回值是函数名
五、函数嵌套(就是函数中还有定义函数)
def father(name):
print('from father %s' %name)
def son():
print('from son')
def grandson():
print('from grandson')
grandson()
son()
father('还是牛')
六、闭包:(在一个作用域中放入的定义变量,就像打了一个包)
#闭包的概念:闭就是封装的意思,就是把变量分装起来;包:就是层的意思,与之前作用域意思是一样的。
#grandson中的变量有name(形式参数);son中的变量有grandson(函数名也是变量);father中的变量有:name(形式参数) son
def father(name):
print('from the father %s' %(name))
def son():
print('from the son')
def grandson():
print('from the grandson %s'%(name))
grandson()
son()
father('SB')
七、装饰器的基本框架
def timmer(func):
def wrapper():
print(func)
func()
return wrapper
def boo():
print('你就是个傻逼!')
res = timmer(boo) # 返回的是wrapper的内存地址 <function timmer.<locals>.wrapper at 0x02129420>
#print(res)
res() #是在执行wrapper 函数
八、装饰器的两种形式:
第一种 无参数的装饰器
user_list=[
{'name':'alex','passwd':'123'},
{'name':'linhaifeng','passwd':'123'},
{'name':'wupeiqi','passwd':'123'},
{'name':'yuanhao','passwd':'123'},
]
current_user={'username':None,'login':False}
def auth_deco(func):
def wrapper(*args,**kwargs):
if current_user['username'] and current_user['login']:
res=func(*args,**kwargs)
return res
username=input('用户名: ').strip()
passwd=input('密码: ').strip()
for index,user_dic in enumerate(user_list):
if username == user_dic['name'] and passwd == user_dic['passwd']:
current_user['username']=username
current_user['login']=True
res=func(*args,**kwargs)
return res
break
else:
print('用户名或者密码错误,重新登录')
return wrapper
@auth_deco
def index():
print('欢迎来到主页面')
@auth_deco
def home():
print('这里是你家')
def shopping_car():
print('查看购物车啊亲')
def order():
print('查看订单啊亲')
print(user_list)
# index()
print(user_list)
home()
第二种 含有参数的装饰器
user_list=[
{'name':'alex','passwd':'123'},
{'name':'linhaifeng','passwd':'123'},
{'name':'wupeiqi','passwd':'123'},
{'name':'yuanhao','passwd':'123'},
]
current_user={'username':None,'login':False}
def auth(auth_type='file'):
def auth_deco(func):
def wrapper(*args,**kwargs):
if auth_type == 'file':
if current_user['username'] and current_user['login']:
res=func(*args,**kwargs)
return res
username=input('用户名: ').strip()
passwd=input('密码: ').strip()
for index,user_dic in enumerate(user_list):
if username == user_dic['name'] and passwd == user_dic['passwd']:
current_user['username']=username
current_user['login']=True
res=func(*args,**kwargs)
return res
break
else:
print('用户名或者密码错误,重新登录')
elif auth_type == 'ldap':
print('巴拉巴拉小魔仙')
res=func(*args,**kwargs)
return res
return wrapper
return auth_deco
#auth(auth_type='file')就是在运行一个函数,然后返回auth_deco,所以@auth(auth_type='file')
#就相当于@auth_deco,只不过现在,我们的auth_deco作为一个闭包的应用,外层的包auth给它留了一个auth_type='file'参数
@auth(auth_type='ldap')
def index():
print('欢迎来到主页面')
@auth(auth_type='ldap')
def home():
print('这里是你家')
def shopping_car():
print('查看购物车啊亲')
def order():
print('查看订单啊亲')
# print(user_list)
index()
# print(user_list)
home()
Python基础之装饰器,python基础装饰
装饰器
1.普通函数
#简单的函数和调用
def a1():
print("i am zhangsan")
def a2():
print("i am lisi")
a1()
a2()
2.在函数前后添加功能
def inner(func):
print("添加1")
func()
print("添加2")
return func
def a1():
print("i am zhangsan")
def a2():
print("i am zhangsan")
a1=inner(a1)
a1()
a2=inner(a2)
a2()
3.使用装饰器
def mywork(func):
def inner():
print("添加1")
func()
print("添加2")
return inner
@mywork # @mywork就等于a1=mywork(a1)
def a1():
print("i am zhangsan")
a1()
#执行时@mywork会把他下面的函数当成mywork函数的参数既mywork(a1),然后在函数inner里执行,inner内func()=a1()
4.装饰带参数的函数
def mywork(func):
def inner(arg):
print("添加1")
func(arg)
print("添加2")
return inner
@mywork
def a1(arg):
print 'i am zhangsan',arg
a1("参数1")
5.装饰动态参数的函数
#合并无参,有参,多参 可以装饰含有N个参数的函数
def mywork(func):
def inner(*args,**kwargs):
print("添加1")
func(*args,**kwargs)
print("添加2")
return inner
@mywork
def a1():
print 'i am zhangsan'
@mywork
def a2(arg):
print 'i am zhangsan',arg
@mywork
def a3(arg1,arg2):
print 'i am zhangsan',arg1,arg2
a1()
a2("参数1")
a3("参数1","参数2")
6.装饰含有返回值的函数
#装饰含有返回值的函数
def mywork(func):
def inner(*args,**kwargs):
print("添加1")
aa=func(*args,**kwargs)
print("添加2")
return aa
return inner
@mywork
def a3(arg1,arg2):
print 'i am zhangsan',arg1,arg2
li=[1,2,3,4,5,6]
return li #返回一个列表
list=a3("参数1","参数2") #list等于inner的返回值
print(list)
#li列表是a3的返回值,所以给在inner函数里执行的func()赋给aa,在通过inner的返回值就能拿到列表
7.装饰器实现登录验证简单原理
def
login(): name =raw_input(“输入用户名:”) if name == “zhangsan”: return
True else: return False def mywork(func): def inner(*args,**kwargs):
lo_login = login() if not lo_login: #如果login()返回的是False return
“用户名错误!” aa=func(*args,**kwargs) return aa return inner @mywork
def a3(arg1,arg2): print ‘i am zhangsan’,arg1,arg2 li=[1,2,3,4,5,6]
return li list=a3(“参数1″,”参数2”) #list等于inner的返回值 print(list)
View Code
8.多个装饰器装饰一个函数
def
newwork1(func): def inner(): print(“newwork1前”) func()
print(“newwork1后”) return inner def newwork2(func): def inner():
print(“newwork2前”) func() print(“newwork2后”) return inner @newwork2
@newwork1 def f1(): print ‘i am zhangsan’ f1() ”’ 输出结果: newwork1前
newwork2前 i am zhangsan newwork2后 newwork1后 ”’ View Code
9.装饰器加参数
#3层装饰器
def Filter(a1,a2):
def outer(func):
def wrapper(request,kargs):
print(a1)
result=func(request,kargs)
print(a2)
return result
return wrapper
return outer
aa=11
bb=22
@Filter(aa,bb)
def Index(request,kargs):
print request,kargs
Index("zhangsan","lisi")
#@Filter(aa,bb)会先执行Filter(aa,bb)函数,获取到返回值outer后拼接成@outer,之后就变成普通的装饰器了
#wrapper函数内可以使用a1,a2,request,kargs 4个参数
装饰器
1.普通函数 # 简单的函数和调用 def a1(): print ( ” i am zhangsan ” ) def
a2(): print ( ” i am lisi ” )a1()a2() 2.在…
Python基础-装饰器,python基础装饰
待更新:
装饰器实例
程序需求:
- 用户最多尝试3次登陆
- 当存在的用户登陆失败3次后,锁定该用户,限制登陆
程序代码:
1 import time
2
3
4 def run_timer(func): #计时器函数
5 def wrapper(*args, **kwargs): #装饰器
6 start = time.time() #开始计时
7 func(*args, **kwargs) #运行程序
8 end = time.time() #停止计时
9 print('Run time is %ss' % (end - start)) #打印程序运行时长
10
11 return wrapper
12
13
14 def identiy():
15 """用户登陆验证程序
16 最多可尝试3次登陆
17 当某一存在的用户输入错误密码3次后,锁定该用户,限制登陆"""
18 with open('account_bak', 'r+') as f_account, open('locked_list', 'a+') as f_locked:
19 f = 0 #程序返回值变量
20 l = [] #被锁定用户列表
21 user_input = [] #输入错误密码的用户名列表
22 count = 0 # 登陆次数计数器
23 flag = True # 登陆循环控制开关
24 while flag and count < 3:
25 name = input('Please input username:') # 输入用户名
26 pwd = input('Please input password:') # 输入用户密码
27 f_locked.seek(0) #"a+"模式打开后,文件位置位于末尾,要遍历文件内容,需要将指针移至文件起始位置
28 for locked_user in f_locked: #将被锁定用户名单写入列表
29 l.append(locked_user.strip())
30 if name in l:
31 print('This user has been locked!') #如果当前欲登陆用户在被锁定列表中,提示并重新输入登陆信息
32 else:
33 user_input.append(name) #将当前输入的用户名加入到列表
34 f_account.seek(0) #循环前将文件位置移至起始位置
35 for line in f_account: #遍历用户登陆数据文件
36 s = eval(line) #将该文件的内容转换为字典格式
37 if name == s['name'] and pwd == s['password']: #判断用户名和密码是否正确
38 print('Authenticate successful') #用户名和密码匹配,认证成功,结束循环,并将f=1返回
39 f = 1
40 flag = False
41 break
42 if f == 1: #用户名和密码不匹配,提示用户输入错误
43 continue
44 print('Wrong name or password!')
45 count += 1 #错误次数加1,当count等于3时,结束循环
46 if len(user_input) == 3: #如果该列表长度等于3,说明用户3次登陆均失败
47 if user_input[0] == user_input[1] == user_input[2]: #判断3次登陆是否时同一用户名
48 f_account.seek(0) #重置文件位置为起始位置
49 l = [] #新建空列表,存放用户登陆文件中的用户名信息
50 for line in f_account: #遍历用户登陆文件
51 s = eval(line) #将行内容转换为字典格式
52 l.append(s['name']) #将用户名加入到列表
53 if user_input[0] in l: #判断登陆失败的用户名是否在上述列表中
54 print('This user has been locked!') #提示用户将锁定该登陆名
55 f_locked.write(user_input[0] + '\n') #将该登录名加入锁定文件
56 f_locked.flush() #实时刷新文件
57 return f
58
59
60 def auth(source):
61 """用户登陆认证程序的装饰器"""
62 def auth_main(func):
63 def wrapper(*args, **kwargs):
64 if source == 'file': #判断认证来源类型是否为‘file’
65 if (identiy() == 1): #调用用户登陆认证程序
66 res = func(*args, **kwargs) #运行被装饰的程序
67 return res
68 elif source == 'ldap': #另外一种认证来源类型
69 def wrapper_2(*args, **kwargs):
70 print('Nothing here!')
71 pass
72 return wrapper
73 return auth_main
74
75
76 @auth(source = 'file') #将用户登陆认证功能装饰程序‘func_1’
77 @run_timer #将程序计时功能装饰程序‘func_1’
78 def func_1(): #被装饰程序
79 time.sleep(1)
80 print('This is function_1')
81
82
83 func_1() #调用被装饰程序
计时+登陆认证 装饰器
验证过程:
- account文件:存放用户登陆数据
- locked_list文件:存放被锁定用户名
当前为空
- 尝试登陆正确的用户
- 尝试不同用户登陆失败
- 尝试同一用户登陆失败
- 尝试同一用户登陆失败,但该用户本身不存在
待更新:
装饰器实例 程序需求: 用户最多尝试3次登陆
当存在的用户登陆失败3次后,锁定该用户,限制…
这是在Python学习小组上介绍的内容,现学现卖、多练习是好的学习方式。
第一步:最简单的函数,准备附加额外功能
# -*- coding:gbk -*-
'''示例1: 最简单的函数,表示调用了两次'''
def myfunc():
print("myfunc() called.")
myfunc()
myfunc()
第二步:使用装饰函数在函数执行前和执行后分别附加额外功能
# -*- coding:gbk -*-
'''示例2: 替换函数(装饰)
装饰函数的参数是被装饰的函数对象,返回原函数对象
装饰的实质语句: myfunc = deco(myfunc)'''
def deco(func):
print("before myfunc() called.")
func()
print(" after myfunc() called.")
return func
def myfunc():
print(" myfunc() called.")
myfunc = deco(myfunc)
myfunc()
myfunc()
第三步:使用语法糖@来装饰函数
# -*- coding:gbk -*-
'''示例3: 使用语法糖@来装饰函数,相当于“myfunc = deco(myfunc)”
但发现新函数只在第一次被调用,且原函数多调用了一次'''
def deco(func):
print("before myfunc() called.")
func()
print(" after myfunc() called.")
return func
@deco
def myfunc():
print(" myfunc() called.")
myfunc()
myfunc()
第四步:使用内嵌包装函数来确保每次新函数都被调用
# -*- coding:gbk -*-
'''示例4: 使用内嵌包装函数来确保每次新函数都被调用,
内嵌包装函数的形参和返回值与原函数相同,装饰函数返回内嵌包装函数对象'''
def deco(func):
def _deco():
print("before myfunc() called.")
func()
print(" after myfunc() called.")
# 不需要返回func,实际上应返回原函数的返回值
return _deco
@deco
def myfunc():
print(" myfunc() called.")
return 'ok'
myfunc()
myfunc()
第五步:对带参数的函数进行装饰
# -*- coding:gbk -*-
'''示例5: 对带参数的函数进行装饰,
内嵌包装函数的形参和返回值与原函数相同,装饰函数返回内嵌包装函数对象'''
def deco(func):
def _deco(a, b):
print("before myfunc() called.")
ret = func(a, b)
print(" after myfunc() called. result: %s" % ret)
return ret
return _deco
@deco
def myfunc(a, b):
print(" myfunc(%s,%s) called." % (a, b))
return a + b
myfunc(1, 2)
myfunc(3, 4)
第六步:对参数数量不确定的函数进行装饰
# -*- coding:gbk -*-
'''示例6: 对参数数量不确定的函数进行装饰,
参数用(*args, **kwargs),自动适应变参和命名参数'''
def deco(func):
def _deco(*args, **kwargs):
print("before %s called." % func.__name__)
ret = func(*args, **kwargs)
print(" after %s called. result: %s" % (func.__name__, ret))
return ret
return _deco
@deco
def myfunc(a, b):
print(" myfunc(%s,%s) called." % (a, b))
return a+b
@deco
def myfunc2(a, b, c):
print(" myfunc2(%s,%s,%s) called." % (a, b, c))
return a+b+c
myfunc(1, 2)
myfunc(3, 4)
myfunc2(1, 2, 3)
myfunc2(3, 4, 5)
第七步:让装饰器带参数
# -*- coding:gbk -*-
'''示例7: 在示例4的基础上,让装饰器带参数,
和上一示例相比在外层多了一层包装。
装饰函数名实际上应更有意义些'''
def deco(arg):
def _deco(func):
def __deco():
print("before %s called [%s]." % (func.__name__, arg))
func()
print(" after %s called [%s]." % (func.__name__, arg))
return __deco
return _deco
@deco("mymodule")
def myfunc():
print(" myfunc() called.")
@deco("module2")
def myfunc2():
print(" myfunc2() called.")
myfunc()
myfunc2()
第八步:让装饰器带 类 参数
# -*- coding:gbk -*-
'''示例8: 装饰器带类参数'''
class locker:
def __init__(self):
print("locker.__init__() should be not called.")
@staticmethod
def acquire():
print("locker.acquire() called.(这是静态方法)")
@staticmethod
def release():
print(" locker.release() called.(不需要对象实例)")
def deco(cls):
'''cls 必须实现acquire和release静态方法'''
def _deco(func):
def __deco():
print("before %s called [%s]." % (func.__name__, cls))
cls.acquire()
try:
return func()
finally:
cls.release()
return __deco
return _deco
@deco(locker)
def myfunc():
print(" myfunc() called.")
myfunc()
myfunc()
第九步:装饰器带类参数,并分拆公共类到其他py文件中,同时演示了对一个函数应用多个装饰器
# -*- coding:gbk -*-
'''mylocker.py: 公共类 for 示例9.py'''
class mylocker:
def __init__(self):
print("mylocker.__init__() called.")
@staticmethod
def acquire():
print("mylocker.acquire() called.")
@staticmethod
def unlock():
print(" mylocker.unlock() called.")
class lockerex(mylocker):
@staticmethod
def acquire():
print("lockerex.acquire() called.")
@staticmethod
def unlock():
print(" lockerex.unlock() called.")
def lockhelper(cls):
'''cls 必须实现acquire和release静态方法'''
def _deco(func):
def __deco(*args, **kwargs):
print("before %s called." % func.__name__)
cls.acquire()
try:
return func(*args, **kwargs)
finally:
cls.unlock()
return __deco
return _deco
# -*- coding:gbk -*-
'''示例9: 装饰器带类参数,并分拆公共类到其他py文件中
同时演示了对一个函数应用多个装饰器'''
from mylocker import *
class example:
@lockhelper(mylocker)
def myfunc(self):
print(" myfunc() called.")
@lockhelper(mylocker)
@lockhelper(lockerex)
def myfunc2(self, a, b):
print(" myfunc2() called.")
return a + b
if __name__=="__main__":
a = example()
a.myfunc()
print(a.myfunc())
print(a.myfunc2(1, 2))
print(a.myfunc2(3, 4))
九,让装饰器带参与同时函数也带参数
#
def login(url,data):#装饰器两个参数
def war(func):
def ck(a): #函数一个参数
a='555' #这里将函数的参数值给改了。
print "Start"
ret = func(a)
print ret
print "End"
return ret
return ck
return war
#函数
@login('123','345')
def to_int(str):
print(str)
print to_int('777') #调用函数
#输出
D:\Python27\python.exe D:/HttpRunnerManager-master/HttpRunnerManager-master/test.py
Start
555
End
555
下面是参考资料,当初有不少地方没看明白,真正练习后才明白些:
1. Python装饰器学习 http://blog.csdn.net/thy38/article/details/4471421
2. Python装饰器与面向切面编程 http://www.cnblogs.com/huxi/archive/2011/03/01/1967600.html
3. Python装饰器的理解 http://apps.hi.baidu.com/share/detail/17572338
1、@property
将某函数,做为属性使用
基础 装饰器,python基础装饰器
今天把学过的装饰器的知识进行回顾一下,说到装饰器,第一反应就是这个东西呢就是用来装逼的,为…
@property 修饰,就是将方法,变成一个属性来使用。
class A():
@property
def pfunc(self):
return self.value
@pfunc.setter
def pfunc(self,value):
self.value = value
@property
def pfunc1(self):
print('this is property')
if __name__=="__main__":
A.pfunc = 9
print A.pfunc
A.pfunc1
2、@classmethod
修饰类的方式
带修饰类方法:cls做为方法的第一个参数,隐式的将类做为对象,传递给方法,调用时无须实例化。
普通函数方法:self做为第一个参数,隐式的将类实例传递给方法,调用方法时,类必须实例化。
class A():
def func(self,x,y):
return x * y
@classmethod
def cfunc(cls,x,y):
return x * y
if __name__=="__main__":
print A().func(5,5)
print A.cfunc(4,5)
3、@staticmethod
修饰类的方式
1)是把函数嵌入到类中的一种方式,函数就属于类,同时表明函数不需要访问这个类
2)使用修饰服,修饰方法,不需要实例化
class A():
def func(self,x,y):
return x * y
@staticmethod
def sfunc(x,y):
return x * y
if __name__=="__main__":
print A.sfunc(6,5)
Linux and
python学习交流1,2群已满.
Linux and
python学习交流3群新开,欢迎加入,一起学习.qq 3群:563227894
不前进,不倒退,停止的状态是没有的.
一起进步,与君共勉,