1.定义:本质是函数,装饰其余函数就是为其余函数添加附加功能。html
2.原则:a.不能修改被装饰的函数的源代码 b.不能修改被装饰的函数的调用方式。 python
实例1:装饰器的使用mysql
1 #Author:http://www.cnblogs.com/Jame-mei 2 #装饰器的使用 3 import time 4 5 6 def timmer(func): 7 def warpper(*args,**kwargs): 8 start_time=time.time() 9 func() 10 stop_time=time.time() 11 print ("The func run time is %s" %(stop_time-start_time)) 12 return warpper 13 14 15 16 17 18 @timmer #等于 time1=timmer(time1),最后再time1() 19 def time1(): 20 time.sleep(2) 21 print ("in the test1...............") 22 23 24 time1()
实例2:一个函数调用另外一个函数,匿名函数的使用nginx
1 #Author:http://www.cnblogs.com/Jame-mei 2 3 def foo(): 4 print ("in the foo") 5 bar() 6 7 8 9 #foo() 调用bar报错,由于要将foo()放到函数的后面,由于Python是解释型语言,须要逐行翻译! 10 11 def bar(): #bar()能够放在调用函数的foo的后面 12 print ("in the bar") 13 14 15 calc=lambda x:x*3 #匿名函数的使用 16 17 foo() 18 19 print (calc(10))
3.实现装饰器的知识储备: git
1).函数即"变量",见下图:程序员
其中变量名x,y和函数名test ,本质他们都是内存中的一个地址,因此函数和变量同样,只不过函数经过()来调用。github
2).高阶函数
a.把一个函数名看成实参传给另一个函数(在不修改被装饰函数的源代码的状况下,为其添加附加功能)
b.返回值中包含函数名(不修改函数的调用方式)redis
实例3:高阶函数的2个功能sql
1 #Author:http://www.cnblogs.com/Jame-mei 2 #高阶函数的2个功能 3 4 import time 5 6 7 8 #1.把一个函数看成实参传给另一个函数 9 def bar(): 10 time.sleep(2.5) 11 print ('in the bar') 12 13 def foo(func): 14 start_time=time.time() 15 func() #bar 的运行时间 16 stop_time=time.time() 17 print ("the func run time is %s" %(stop_time-start_time)) 18 19 20 #foo() 原来的调用方式 21 foo(bar) 22 ------------------------------------output--------------------------------------------------- 23 24 in the bar 25 the func run time is 2.500143051147461 26 27 Process finished with exit code 0
1 #Author:http://www.cnblogs.com/Jame-mei 2 #高阶函数的2个功能 3 #2.返回值中包含函数 4 5 def bar(): 6 time.sleep(2.5) 7 print ('in the bar') 8 9 def test2(func): 10 print (func) #打印的是内存地址 11 return func #返回之中包含函数!! 12 13 14 15 16 bar=test2(bar) 17 bar() #表明bar(),打印print
3).嵌套函数和做用域 json
高阶函数+嵌套函数=装饰器
1 def foo(): 2 print ('in the foo()') 3 def bar(): #在函数内定义另外一个函数def ,至关于foo()函数的局部变量。 4 print ('in the bar()') 5 6 bar() #局部变量只能在内部调用!! 7 8 9 10 foo()
1 #Author:http://www.cnblogs.com/Jame-mei 2 #嵌套函数的全局做用域和局部做用域 3 x=0 4 def grandpa(): 5 x=1 6 def dad(): 7 x=2 8 def son(): 9 x=3 10 print (x) 11 son() 12 dad() 13 14 grandpa() 15 print (x)
1 def bar2(): 2 print ('in the bar2') 3 4 def foo2(): 5 print ('in the foo2') 6 bar2() #这叫函数的调用,这里要区别与函数的嵌套!
1 #Author:http://www.cnblogs.com/Jame-mei 2 import time 3 #写一个装饰器,用高阶函数+函数嵌套来实现 4 5 6 def timmer(func): 7 def deco(*args,**kwargs): #*args,**kwargs,不管被装饰的函数有多少参数均可以代替。 8 start_time=time.time() 9 func(*args,**kwargs) 10 stop_time=time.time() 11 print ('the func run time is %s'%(stop_time-start_time)) 12 13 return deco #高阶函数返回一个函数名 14 15 16 @timmer # 等于test1=timmer(test1) 17 def test1(): 18 time.sleep(1.123) 19 print ('in the test1...') 20 21 22 @timmer 23 def test2(name,age): 24 time.sleep(2.256) 25 print ('in the test2',name,age) 26 27 28 29 30 31 32 33 34 #用手动的方式来实现装饰器的功能,@timmer的方式来装饰test1(),test2() 35 # test1=timmer(test1) #把函数名看成实参,传给另外一个函数 36 # test2=timmer(test2) 37 38 # print (test1) 39 # print (test2) 40 41 test1() 42 43 test2('Alex',22)
1 #Author:http://www.cnblogs.com/Jame-mei 2 3 user,passwd='alex','abc123' 4 5 def auth(auth_type): 6 7 def outwrapper(func): 8 9 def wrapper(*args, **kwargs): 10 if auth_type=='local': 11 username = input("username:").strip() 12 password = input("password:").strip() 13 if user == username and passwd == password: 14 print("\033[32;1m User has passwd authentication \033[0m") 15 res = func(*args, **kwargs) 16 print('------------->after authentication') 17 return res 18 else: 19 exit("\033[31;1m Ivalid username or password \033[Om") 20 elif auth_type=='ldap': 21 print ('This ldap is disable...') 22 23 return wrapper 24 return outwrapper 25 26 27 28 29 def index(): 30 print ('welcome in the index page') 31 32 @auth(auth_type='local') 33 def home(): 34 print ('welcome %s home page' %user) 35 return 'return from home!' 36 37 38 @auth(auth_type='ldap') 39 def bbs(): 40 print('welcome %s bbs page' %user) 41 42 43 44 #调用,index不用装饰器,home打印返回值,bbs来验证local和ldap的差异 45 index() 46 print(home()) 47 bbs()
4.Alex的装饰器之旅
1):装饰器之旅1
1 #Author:http://www.cnblogs.com/Jame-mei 2 3 #1.模版 4 '''def home(): 5 print("---首页----") 6 7 8 def america(): 9 print("----oumei专区----") 10 11 12 def japan(): 13 print("----rihan专区----") 14 15 16 def henan(): 17 print("----北上广深专区----") 18 19 更改需求: 20 21 想收费得先让其进行用户认证,认证经过后,再断定这个用户是不是VIP付费会员就能够了,是VIP就让看,不是VIP就不让看就好了呗。 22 你以为这个需求非常简单,由于要对多个版块进行认证,那应该把认证功能提取出来单独写个模块,而后每一个版块里调用 就能够了, 23 与是你轻轻的就实现了下面的功能 。 24 ''' 25 #更改后代码以下: 26 user_status=False #若是认证后,修改成True 27 28 29 def login(): 30 _username='alex' #假设db中有这2个帐号 31 _password='abc123' 32 global user_status 33 if user_status==False: 34 username=input('please input your username:') 35 password=input('please input your password:') 36 37 if username==_username and password==_password: 38 print ('welcome %s login!' %username) 39 else: 40 print ('input username or password error!') 41 else: 42 print ('用户已登录,请勿重复操做!') 43 44 45 def home(): 46 print("---首页----") 47 48 49 def america(): 50 login() #执行前加上验证 51 print("----oumei专区----") 52 53 54 def rihan(): 55 print("----rihan专区----") 56 57 58 def bsgs(): 59 login() #执行前加上验证 60 print("----北上广深专区----") 61 62 63 home() 64 america() 65 bsgs()
此时你信心满满的把这个代码提交给你的TEAM LEADER审核,没成想,没过5分钟,代码就被打回来了。
TEAM LEADER给你反馈是,我如今有不少模块须要加认证模块,你的代码虽然实现了功能,可是须要更改须要加认证的各个模块的代码,
这直接违反了软件开发中的一个原则“开放-封闭”原则,简单来讲,它规定已经实现的功能代码不容许被修改,但能够被扩展,即:
封闭:已实现的功能代码块不该该被修改
开放:对现有功能的扩展开放
这个原则你仍是第一次据说,我擦,再次感觉了本身这个野生程序员与正规军的差距,BUT ANYWAY,老大要求的这个怎么实现呢?
如何在不改原有功能代码的状况下加上认证功能呢?你一时想不出思路,只好带着这个问题回家继续憋,媳妇不在家,去隔壁老王家串门了,
你正好落的清静,一不当心就想到了解决方案,不改源代码能够呀,
你师从沙河金角大王时,记得他教过你,高阶函数,就是把一个函数当作一个参数传给另一个函数,当时大王说。
有一天,你会用到它的,没想到这时这个知识点忽然从脑子 里蹦出来了,我只须要写个认证方法,每次调用 须要验证的功能时,
直接 把这个功能 的函数名当作一个参数 传给 个人验证模块不就好了么,哈哈,机智如我,如是你啪啪啪改写了以前的代码
2):装饰器之旅2
1 #Author:http://www.cnblogs.com/Jame-mei 2 3 user_status = False # 用户登陆了就把这个改为True 4 5 6 def login(func): # 把要执行的模块从这里传进来 7 _username = "alex" # 伪装这是DB里存的用户信息 8 _password = "abc!23" # 伪装这是DB里存的用户信息 9 global user_status 10 11 if user_status == False: 12 username = input("user:") 13 password = input("pasword:") 14 15 if username == _username and password == _password: 16 print("welcome login....") 17 user_status = True 18 else: 19 print("wrong username or password!") 20 21 if user_status == True: 22 func() # 看这里看这里,只要验证经过了,就调用相应功能 23 24 25 def home(): 26 print("---首页----") 27 28 29 def america(): 30 # login() #执行前加上验证 31 print("----欧美专区----") 32 33 34 def japan(): 35 print("----日韩专区----") 36 37 38 def henan(): 39 # login() #执行前加上验证 40 print("----河南专区----") 41 42 43 home() 44 login(america) # 须要验证就调用 login,把须要验证的功能 当作一个参数传给login 45 46 # home() 47 # america() 48 login(henan)
你改变了调用方式呀, 想想,如今没每一个须要认证的模块,都必须调用你的login()方法,并把本身的函数名传给你,人家以前可不是这么调用 的, 试想,若是 有100个模块须要认证,那这100个模块都得更改调用方式,这么多模块确定不止是一我的写的,让每一个人再去修改调用方式 才能加上认证,你会被骂死的。
3):装饰器之旅3
home()
america
=
login(america)
#你在这里至关于把america这个函数替换了
henan
=
login(henan)
#那用户调用时依然写
america()
|
但问题在于,还不等用户调用 ,你的america = login(america)就会先本身把america执行了呀。。。。,你应该等我用户调用 的时候 再执行才对呀,不信我试给你看。。。
老王:哈哈,你说的没错,这样搞会出现这个问题? 但你想一想有没有解决办法 呢?
你:我擦,你指的思路呀,大哥。。。我哪知道 下一步怎么走。。。
老王:算了,估计你也想不出来。。。 学过嵌套函数没有?
你:yes,而后呢?
老王:想实现一开始你写的america = login(america)不触发你函数的执行,只须要在这个login里面再定义一层函数,第一次调用america = login(america)只调用到外层login,这个login虽然会执行,但不会触发认证了,由于认证的全部代码被封装在login里层的新定义 的函数里了,login只返回 里层函数的函数名,这样下次再执行america()时, 就会调用里层函数啦。详见代码:
1 def login(func): #把要执行的模块从这里传进来 2 3 def inner():#再定义一层函数 4 _username = "alex" #伪装这是DB里存的用户信息 5 _password = "abc!23" #伪装这是DB里存的用户信息 6 global user_status 7 8 if user_status == False: 9 username = input("user:") 10 password = input("pasword:") 11 12 if username == _username and password == _password: 13 print("welcome login....") 14 user_status = True 15 else: 16 print("wrong username or password!") 17 18 if user_status == True: 19 func() # 看这里看这里,只要验证经过了,就调用相应功能 20 21 return inner #用户调用login时,只会返回inner的内存地址,下次再调用时加上()才会执行inner函数 22 23 24 25 还能够更简单 26 27 能够把下面代码去掉 28 29 america = login(america) #你在这里至关于把america这个函数替换了 30 只在你要装饰的函数上面加上下面代码 31 32 @login 33 def america(): 34 #login() #执行前加上验证 35 print("----欧美专区----") 36 37 def japan(): 38 print("----日韩专区----") 39 40 @login 41 def henan(): 42 #login() #执行前加上验证 43 print("----河南专区----")
你:老王,老王,怎么传个参数就不行了呢?
老王:那必然呀,你调用henan时,实际上是至关于调用的login,你的henan第一次调用时henan = login(henan), login就返回了inner的内存地址,第2次用户本身调用henan("3p"),实际上至关于调用的时inner,但你的inner定义时并无设置参数,但你给他传了个参数,因此天然就报错了呀
你:可是个人 版块须要传参数呀,你不让我传不行呀。。。
老王:没说不让你传,稍作改动即可。
老王:你再试试就行了 。
你: 果真好使,大神就是大神呀。 。。 不过,若是有多个参数呢?
老王:。。。。老弟,你不要什么都让我教你吧,非固定参数你没学过么? *args,**kwargs...
你:噢 。。。还能这么搞?,nb,我再试试。
彻底遵循开放-封闭原则,最终代码以下 。
1 user_status = False #用户登陆了就把这个改为True 2 3 def login(func): #把要执行的模块从这里传进来 4 5 def inner(*args,**kwargs):#再定义一层函数 6 _username = "alex" #伪装这是DB里存的用户信息 7 _password = "abc!23" #伪装这是DB里存的用户信息 8 global user_status 9 10 if user_status == False: 11 username = input("user:") 12 password = input("pasword:") 13 14 if username == _username and password == _password: 15 print("welcome login....") 16 user_status = True 17 else: 18 print("wrong username or password!") 19 20 if user_status == True: 21 func(*args,**kwargs) # 看这里看这里,只要验证经过了,就调用相应功能 22 23 return inner #用户调用login时,只会返回inner的内存地址,下次再调用时加上()才会执行inner函数 24 25 26 def home(): 27 print("---首页----") 28 29 @login 30 def america(): 31 #login() #执行前加上验证 32 print("----欧美专区----") 33 34 def japan(): 35 print("----日韩专区----") 36 37 # @login 38 def henan(style): 39 ''' 40 :param style: 喜欢看什么类型的,就传进来 41 :return: 42 ''' 43 #login() #执行前加上验证 44 print("----河南专区----") 45 46 home() 47 # america = login(america) #你在这里至关于把america这个函数替换了 48 henan = login(henan) 49 50 # #那用户调用时依然写 51 america() 52 53 henan("3p")
要容许用户选择用qq\weibo\weixin认证,此时的你,已深谙装饰器各类装逼技巧,轻松的就实现了新的需求:
1 #_*_coding:utf-8_*_ 2 3 4 user_status = False #用户登陆了就把这个改为True 5 6 def login(auth_type): #把要执行的模块从这里传进来 7 def auth(func): 8 def inner(*args,**kwargs):#再定义一层函数 9 if auth_type == "qq": 10 _username = "alex" #伪装这是DB里存的用户信息 11 _password = "abc!23" #伪装这是DB里存的用户信息 12 global user_status 13 14 if user_status == False: 15 username = input("user:") 16 password = input("pasword:") 17 18 if username == _username and password == _password: 19 print("welcome login....") 20 user_status = True 21 else: 22 print("wrong username or password!") 23 24 if user_status == True: 25 return func(*args,**kwargs) # 看这里看这里,只要验证经过了,就调用相应功能 26 else: 27 print("only support qq ") 28 return inner #用户调用login时,只会返回inner的内存地址,下次再调用时加上()才会执行inner函数 29 30 return auth 31 32 def home(): 33 print("---首页----") 34 35 @login('qq') 36 def america(): 37 #login() #执行前加上验证 38 print("----欧美专区----") 39 40 def japan(): 41 print("----日韩专区----") 42 43 @login('weibo') 44 def henan(style): 45 ''' 46 :param style: 喜欢看什么类型的,就传进来 47 :return: 48 ''' 49 #login() #执行前加上验证 50 print("----河南专区----") 51 52 home() 53 # america = login(america) #你在这里至关于把america这个函数替换了 54 #henan = login(henan) 55 56 # #那用户调用时依然写 57 america() 58 59 # henan("3p") 60 61 带参数的装饰器
更多装饰器黄段子,请访问导师Alex:http://www.cnblogs.com/alex3714/articles/5765046.html
5.装饰器的练习操做(重要)
1):无参装饰器
import time def timmer(func): # func=index def wrapper(*args,**kwargs): start=time.time() res=func(*args,**kwargs) stop=time.time() print('run time is %s' %(stop - start)) return res return wrapper def outter(func): def inner(*args,**kwargs): res=func(*args,**kwargs) return res return inner @timmer #index=timmer(index) def index(): print('welcome to index page') time.sleep(3) @timmer #home=timmer(home) def home(name): print('welecom %s ' %name) time.sleep(2) return 123 index() # wrapper() res=home('egon') # res=wrapper('egon')
2):认证功能装饰器实现
import time current_userinfo={'user':None} def outter(func): def wrapper(*args,**kwargs): if current_userinfo['user']: return func(*args,**kwargs) user=input('please input you username: ').strip() pwd=input('please input you password: ').strip() if user == 'egon' and pwd == '123': print('login successfull') # 保存登陆状态 current_userinfo['user']=user res=func(*args,**kwargs) return res else: print('user or password err') return wrapper @outter # index=outter(index) def index(): print('welcome to index page') time.sleep(3) @outter #home=outter(home) def home(name): print('welecom %s ' %name) time.sleep(2) return 123 index() # wrapper() res=home('egon') # res=wrapper('egon')
3):一个函数添加多个装饰器的生效顺序
import time current_userinfo={'user':None} def timmer(func): #func=最原始的index指向的内存地址 def wrapper2(*args,**kwargs): print('wrapper2.....') start=time.time() res=func(*args,**kwargs) # func=最原始的index指向的内存地址 stop=time.time() print('run time is %s' %(stop - start)) return res return wrapper2 def outter(func): # func=wrapper2 def wrapper1(*args,**kwargs): print('wrapper1.....') if current_userinfo['user']: return func(*args,**kwargs) user=input('please input you username: ').strip() pwd=input('please input you password: ').strip() if user == 'egon' and pwd == '123': print('login successfull') # 保存登陆状态 current_userinfo['user']=user res=func(*args,**kwargs) # func=wrapper2 return res else: print('user or password err') return wrapper1 # 解释语法的时候应该自下而上 # 执行时则是自上而下 # 能够连续写多个装饰器,处于最顶层的装饰器先执行 @outter # index=outter(wrapper2) # index=wrapper1 @timmer # timmer(最原始的index指向的内存地址) ==>wrapper2 def index(): print('welcome to index page') time.sleep(3) index() #wrapper1()
4):有参装饰器的使用
import time current_userinfo={'user':None} def auth(engine='file'): def outter(func): #func=最原始的index def wrapper(*args,**kwargs): if engine == 'file': if current_userinfo['user']: return func(*args,**kwargs) user=input('please input you username: ').strip() pwd=input('please input you password: ').strip() if user == 'egon' and pwd == '123': print('login successfull') # 保存登陆状态 current_userinfo['user']=user res=func(*args,**kwargs) return res else: print('user or password err') elif engine == 'mysql': print('mysql 的认证机制') elif engine == 'ldap': print('ldap 的认证机制') else: print('不支持该engine') return wrapper return outter @auth(engine='mysql') #@outter # index=outter(最原始的index) # index= wrapper def index(): print('welcome to index page') time.sleep(3) @auth(engine='ldap') def home(name): print('welecom %s ' %name) time.sleep(2) return 123 index() #warpper() home('egon') #wrapper('egon')
5):wraps装饰器使用
import time from functools import wraps def timmer(func): @wraps(func) def wrapper(*args,**kwargs): start=time.time() res=func(*args,**kwargs) stop=time.time() print('run time is %s' %(stop - start)) return res # wrapper.__doc__ = func.__doc__ # wrapper.__name__= func.__name__ return wrapper @timmer def index(): """ 这是一个index函数 :return: """ print('welcome to index page') time.sleep(1) return 123 print(help(index)) # index.__doc__ print(index.__name__) # res=index() # print(res)
*什么是迭代器?
迭代是一个重复的过程,每一次重复都是基于上一次结果二进行的。
#单纯的重复并非迭代:
while True:
print('=====>>>')
*为何要用迭代器?
找到一种不依赖于索引的取值方式。
*怎么用迭代器?
a.#可迭代对象?
在python中,但凡内置有__iter__()方法对象,都是可迭代对象。
例如:字符串str,列表list,元祖tuple,字典dict,集合set,文件open等有__iter__()方法的可迭代对象。
b.#迭代器对象?
执行可迭代对象下的__iter__()方法获得的返回值就是一个迭代器对象。
迭代器对象中内置有__next__()方法可迭代取值!
因此:同时内置有 __next__()方法 和 __iter__()方法的才叫作迭代器对象!
例如:
d=[1,2,4]
iter_obj=d.__iter__()
print(iter_obj) #<list_iterator object at 0x000000000284A390>
print(iter_obj.__next__())#依次取出d列表中的值,当取完的时候会抛出一个StopIteration的结束信号!
dict={'a':1,'b':2,'c':3,'d':4} iter_obj=dict.__iter__() while True: try: print(iter_obj.__next__()) except StopIteration: break ''' output: a b c d '''
由上面例子可知:for 循环底层运行机制,for 循环能够称为迭代器循环。
1.先调用in 后面对象的__iter__()方法,获得该对象的迭代器对象。
2.执行迭代器对象的__next__()方法,将获得的返回值赋值给in前面的变量,而后执行一次循环体代码。
3.循环往复,直到取干净迭代器内的全部值,自动捕捉结束循环。
c.#迭代器的优缺点
优势:
1.提供一种不依赖于索引的迭代取值方式
2.更加节省内存空间
缺点:
1.是一次性的,值去干净后没法再次取值,除非从新获得新的迭代器对象。
2.只能日后取值,不能往前取值,永远没法预测迭代器的长度。(不如索引的取值的方式灵活)
a.什么是生成器?
在函数体内但凡是有yield关键字,再调用函数就不会执行函数体代码,获得返回值就是一个生成器对象.
生成器本质上就是迭代器!!
实例:
def foo(): print('first') yield 1 print('second') yield 2 print('three') g=foo() print(g) #<generator object foo at 0x00000000024958E0> print(g.__iter__()) #<generator object foo at 0x00000000024958E0> res1=next(g) #first res2=next(g) #second print(res1) #1 print(res2) #2 #等价于print(g.__next__()) 当res3=next(g)取不到值的时候会报错,跟迭代器同样。 #生成器本质上就是迭代器!
def foo(): print('first') yield 1 print('second') yield 2 print('three') g=foo() for item in g: print(item)
next(g)过程:
会触生成器g 所对应的函数的执行,知道遇到yiled才停下来,而后吧yiled后面的返回值看成本次next操做的结果!
b.为何要用生成器?
学习生成器是为了掌握一种自定义迭代器的方式!
1.实例:用yield实现range()函数的方法,就叫作自定义迭代器。。。
#用yield 实现range函数的功能 def my_range(start,stop,step=1): print('开始运行') while start<stop: yield start start+=step print('结束运行') res=my_range(1,1000,2) print(res.__next__()) print(res.__next__()) print(res.__next__()) ''' 开始运行 1 3 5 ''' # for i in res: # print(i)
2.yiled表达式应用
实例1:yield的使用,给dog喂包子...
def dog(name): food_list=[] print('狗哥 %s 准备开吃'%name) while True: food=yield food_list #暂停 yield=None print('狗哥%s 开始吃了%s'%(name,food)) food_list.append(food) g=dog('alex') # next(g)#狗哥 alex 准备开吃 # next(g) #狗哥alex 开始吃了None # next(g)#狗哥alex 开始吃了None g.send(None)#等价于next(g),由于使用是第一次必须传入None!! #狗哥 alex 准备开吃,返回值为None res1=g.send('骨头') #send先传值,再next(g) 狗哥alex 开始吃了骨头 print(res1) res2=g.send('泔水') print(res2) res3=g.send('米饭') print(res3) #g.close() #关闭链接
实例2:yield实现协程函数
#yield关键字的另一种使用形式:表达式形式的yield def eater(name): print('%s 准备开始吃饭啦' %name) food_list=[] while True: food=yield food_list print('%s 吃了 %s' % (name,food)) food_list.append(food) g=eater('egon') g.send(None) #对于表达式形式的yield,在使用时,第一次必须传None,g.send(None)等同于next(g) g.send('蒸羊羔') g.send('蒸鹿茸') g.send('蒸熊掌') g.send('烧素鸭') g.close() g.send('烧素鹅') g.send('烧鹿尾')
实例3:用装饰器来实现初始化协程函数(next(g) /g.send(None))
1 def init(func): 2 def wrapper(*args,**kwargs): 3 g=func(*args,**kwargs) 4 next(g) 5 return g 6 return wrapper 7 8 9 10 11 @init 12 def eater(name): 13 print('%s 准备开始吃饭了'%name) 14 food_list=[] 15 while True: 16 food=yield food_list 17 print('%s 吃了 %s '%(name,food)) 18 food_list.append(food) 19 20 21 22 g=eater('egon') 23 #g.send(None) #用@init能够替代初始化传入None值的操做 24 g.send('蒸羊羔') 25 ''' 26 egon 准备开始吃饭了 27 egon 吃了 蒸羊羔 28 '''
总结yield:
1.yield提供一种自定义迭代器的方式
2.与return 对比,都能返回多个值,都没有类型限制,而return只能返回一次值,而yiled能够返回屡次值(yield能够帮我卖保存函数的执行状态或结果,以便下次迭代使用)
生成器表达式的应用:
''' 用生成器实现range函数的功能 ''' #1.应用1 def my_range(start,stop,step=1): while start<stop: yield start start+=step for item in my_range(1,5,2): print(item) #2.应用2 def dog(name): print('狗哥:%s 准备开始'%name) food_list=[] while True: food=yield food_list print('狗哥%s 吃了:%s'%(name,food)) food_list.append(food) #print(food_list) dg=dog('egon') res0=next(dg) #初始化yield的时候必须给一个None值! print(res0) res1=dg.send('骨头') print(res1) res2=dg.send('泔水') print(res2) res3=dg.send('馒头') print(res3) #3.生成器表达式应用 #列表表达式 # l=[i**2 for i in range(1,11)] # print(l) names=['egon','alex','lxx'] g_name=(name.upper() for name in names if name!='egon') print(g_name) #<generator object <genexpr> at 0x0000000002455A40> print(next(g_name)) with open('a.txt','rt',encoding='utf-8') as f: # g_lines=(line for line in f) # print(next(g_lines)) # g_lines=(len(line) for line in f) # print(max(g_lines)) print(max(len(line) for line in f))
1.请参考内置函数官方文档或者相关文档
菜鸟教程:http://www.runoob.com/python3/python3-built-in-functions.html
2.部份内置函数实例练习
1):frozenset内置函数
2):hash函数的原理
3).部分其余函数
1 #Author:http://www.cnblogs.com/Jame-mei 2 3 #1.匿名函数lanbda 方式1 4 #(lambda n:print(n)) (5) 5 6 #匿名函数lanbda 方式2,不能作循环或者迭代,只能进行简单的三元运算! 7 calc=lambda n:n*2 8 #print(calc(10)) #输出20 9 10 11 #2.filter() 函数用于过滤序列,过滤掉不符合条件的元素,返回由符合条件元素组成的新列表。 与匿名函数结合使用以下: 12 ''' 13 res = filter(lambda n:n>5,range(10)) 14 for i in res: 15 print (i) 16 17 输出: 18 6 19 7 20 8 21 9 22 ''' 23 24 25 '''#3.map函数的使用:map() 会根据提供的函数对指定序列作映射。 26 res=map(lambda n:n*n,range(10)) #等价于res1=[i*2 for i in range(10)]和res2=[lambda i:i*2,range(10)] 27 for i in res: 28 print (i) 29 30 输出: 31 0 32 1 33 4 34 9 35 16 36 25 37 36 38 49 39 64 40 81 41 ''' 42 43 '''#4.reduce 在python2.x中属于内置函数,可是在python3.x中已经移动到了functools 44 import functools 45 res=functools.reduce(lambda x,y:x*y,range(1,5)) 46 print(res) 47 输出: 48 24 49 ''' 50 51 52 '''#5.frozenset() 冻结 53 res1=([1,1,22,22,3,3]) 54 res2=frozenset([1,1,22,22,3,3]) 55 ''' 56 57 58 '''#5.globals() 函数会以字典类型返回当前位置的所有全局变量。''' 59 print (globals()) 60 61 62 '''#6.pow() 方法返回 xy(x的y次方) 的值 63 print (pow(2,3)) #输出8''' 64 65 '''#7.repr() 函数将对象转化为供解释器读取的形式。''' 66 dict = {'runoob': 'runoob.com', 'google': 'google.com'} 67 print (repr(dict)) 68 69 70 '''#8.reversed 函数返回一个反转的迭代器。''' 71 72 '''#9.round() 方法返回浮点数x的四舍五入值。''' 73 print (round(4.25)) 74 print (round(4.78)) 75 print (round(3.78)) 76 77 78 '''#10.sorted()排序....''' 79 sor={-5:3,6:2,1:10,9:5,7:4} 80 print (sor) 81 #print (sorted(sor.items())) 默认按照Key排序 82 print (sorted(sor.items(),key=lambda x:x[1])) #按照value来进行排序! 83 84 85 '''#11.type() 函数若是你只有第一个参数则返回对象的类型,三个参数返回新的类型对象。''' 86 87 88 '''#12.zip()函数''' 89 a=[1,2,3,4] 90 b=['a','b','c','d'] 91 for i in zip(a,b): 92 print (i) 93 94 95 '''#13.import decorator 96 __import__('decorator') 97 98 输出: 99 in the test1............... 100 The func run time is 2.0011146068573 101 '''
1.参考 http://www.cnblogs.com/alex3714/articles/5161349.html
2.json序列化和反序列化操做实例
1):json序列化和反序列化
实例1:序列化和反序列化前奏
1 #Author:http://www.cnblogs.com/Jame-mei 2 3 ''' 4 #1.序列化,将内存的对象,变成字符串存起来 5 6 info={ 7 'name':'alex', 8 'age':24 9 10 } 11 f=open('json1.txt','w') 12 f.write(str(info)) 13 f.close() 14 ''' 15 16 #2.反序列化,将字符串取出来 17 f=open('json1.txt','r') 18 data=eval(f.read()) #直接r.read()是一个字符串类型,想要输出以前的字典,须要用eval()函数。 19 print (data['name']) 20 f.close() 21 22 #以上转换方法太low了,请看json02.py内容!
实例2:json实现序列化和反序列化
1 #Author:http://www.cnblogs.com/Jame-mei 2 import json 3 4 ''' 5 #1.序列化 6 info={ 7 'name':'alex', 8 'age':24 9 10 } 11 f=open('json2.txt','w') 12 # print (json.dumps(info)) #打印出来是字符串 13 f.write(json.dumps(info)) 14 f.close() 15 ''' 16 17 18 #2.反序列化 19 f=open('json2.txt','r') 20 #print (json.loads(f.read())) 21 data=json.loads(f.read()) 22 print (data['name']) 23 print (data['age'])
实例3:json只能处理简单的数据类型
1 #Author:http://www.cnblogs.com/Jame-mei 2 import json 3 4 def sayhi(name): 5 print ('hello ',name) 6 7 8 info={ 9 'name':'alex', 10 'age':24, 11 'func':sayhi 12 } 13 14 f=open('json3.txt','w') 15 f.write(json.dumps(info)) 16 f.close() 17 18 19 '''总结:1.序列化def会报错,TypeError: Object of type 'function' is not JSON serializable。 20 2.json只能处理简单的数据类型,例如字典,列表,字符串等。 21 3.想要处理更加复杂的,须要用到pickle,用法跟json彻底同样。 22 '''
实例4:json处理序列化和反序列化最好单个任务只进行一次
1 #Author:http://www.cnblogs.com/Jame-mei 2 import json 3 4 ''' 5 #1.dumps屡次,进行序列化,修改其中的元素再次dumps,发现存了2个字典进去。 6 def sayhi(name): 7 print ('hello ',name) 8 9 10 info={ 11 'name':'alex', 12 'age':24, 13 #'func':sayhi 14 } 15 16 f=open('json5.txt','w') 17 f.write(json.dumps(info)) 18 19 info['age']=26 #修改info的内容,再次进行dumps 20 f.write(json.dumps(info)) 21 22 f.close() 23 ''' 24 25 f=open('json5.txt','r') 26 data=json.loads(f.read()) 27 print (data) 28 #json.decoder.JSONDecodeError: Extra data: line 1 column 28 (char 27) 29 30 31 '''总结: 32 经过以上序列化和反序列化操做,dumps能够屡次进行,可是loads后会报错,能够循环打印出来,可是不能打印出每次dumps的。 33 因此,最好每次dumps()和loads(),每次序列化和反序列化只进行一次,有新的内容再从新进行存取操做。 34 35 36 '''
3.pickle
1):实例1:pickle序列化和反序列化操做
1 import pickle 2 3 4 '''#1.序列化 5 def sayhi(name): 6 print ('hello ',name) 7 8 9 info={ 10 'name':'alex', 11 'age':24, 12 'func':sayhi 13 } 14 15 f=open('json3.txt','wb') #若是只是w,会报TypeError: write() argument must be str, not bytes 16 f.write(pickle.dumps(info)) 17 f.close() 18 ''' 19 20 def sayhi(name): 21 print ('hello ',name) 22 23 f=open('json3.txt','rb') 24 data=pickle.loads(f.read()) 25 #AttributeError: Can't get attribute 'sayhi' on <module '__main__' from 'E:/pythonwork/s14/day04/pickle01.py'> 26 #sayhi随着函数执行后,会从内存中消失,且func:sayhi也不该该这用,须要手动将def sayhi()函数copy过来。 27 print (data['name']) 28 print (data) 29 print (data['func']('caiyunhua')) #执行func对应的函数!
2):实例2:pickle精简版序列化和反序列化
1 #Author:http://www.cnblogs.com/Jame-mei 2 import pickle 3 4 5 #1.精简版pickle序列化 6 def sayhi(name): 7 print ('hello ',name) 8 9 10 info={ 11 'name':'alex', 12 'age':24, 13 'func':sayhi 14 } 15 16 f=open('json4.txt','wb') 17 pickle.dump(info,f) #这步至关于pickle01中的f.write(pickle.dumps(info))序列化操做! 18 f.close() 19 20 21 f1=open('json4.txt','rb') 22 data=pickle.load(f1) #这步至关于pickle02中的 data=pickle.loads(f.read()) 23 print (data['name']) 24 print (data) 25 print (data['func']('tom'))
1.三元表达式
语法:# res=条件成立时的返回值 if 条件 else 条件不成立时的返回值
例子:比较两个大小:
1):用函数来实现: def max2(x,y): if x>y: return x else: return y res=max2(1,2) 2):用三元表达式实现 x=1 y=2 res=x if x>y else y print(res) res=True if x>y else False print(res)
2.列表生成式
语法:# [ 条件成立的列表 循环体 判断条件]
例子: 过滤符合条件的数字列表,过滤添加符合条件的字符列表
1.生成一个0-10大于3的新列表 l1=[i for i in range(10) if i > 3] print(l1) 2.将一个列表过滤,生成一个新的列表 names=['alex_sb','egon','liuqingzheng_sb','wupeiqi_sb'] l2=[] for name in names: if name.endswith('sb'): l.append(name.upper()) print(l2) names=[name.upper() for name in names if name.endswith('sb')] print(names)
3.字典生成式
语法:#{i:i 循环体 过滤条件}
例子:从数字中快速生成一个字典,将一个列表格式快速生成字典
#1.生成一个纯数字的字典 dic1={i:i for i in range(10) if i>3} print(dic1) #2.将一个列表快速生成为一个字典 l1=[ ['name','egon'], ['age',18], ['sex','male'] ] dic2={} dic2={item[0]:item[1] for item in l1} print(dic2)
"设计项目目录结构",就和"代码编码风格"同样,属于我的风格问题。对于这种风格上的规范,一直都存在两种态度:
我是比较偏向于后者的,由于我是前一类同窗思想行为下的直接受害者。我曾经维护过一个很是很差读的项目,其实现的逻辑并不复杂,可是却耗费了我很是长的时间去理解它想表达的意思。今后我我的对于提升项目可读性、可维护性的要求就很高了。"项目目录结构"其实也是属于"可读性和可维护性"的范畴,咱们设计一个层次清晰的目录结构,就是为了达到如下两点:
因此,我认为,保持一个层次清晰的目录结构是有必要的。更况且组织一个良好的工程目录,实际上是一件很简单的事儿。
关于如何组织一个较好的Python工程目录结构,已经有一些获得了共识的目录结构。在Stackoverflow的这个问题上,能看到你们对Python目录结构的讨论。
这里面说的已经很好了,我也不打算从新造轮子列举各类不一样的方式,这里面我说一下个人理解和体会。
假设你的项目名为foo, 我比较建议的最方便快捷目录结构这样就足够了:
Foo/ |-- bin/ | |-- foo |
|----com |
|-- foo/ | |-- tests/ | | |-- __init__.py | | |-- test_main.py | | | |-- __init__.py | |-- main.py | |-- docs/ | |-- conf.py | |-- abc.rst | |-- setup.py |-- requirements.txt |-- README
简要解释一下:
bin/
: 存放项目的一些可执行文件,固然你能够起名script/
之类的也行。foo/
: 存放项目的全部源代码。(1) 源代码中的全部模块、包都应该放在此目录。不要置于顶层目录。(2) 其子目录tests/
存放单元测试代码; (3) 程序的入口最好命名为main.py
。docs/
: 存放一些文档。setup.py
: 安装、部署、打包的脚本。requirements.txt
: 存放软件依赖的外部Python包列表。README
: 项目说明文件。
除此以外,有一些方案给出了更加多的内容。好比LICENSE.txt
,ChangeLog.txt
文件等,我没有列在这里,由于这些东西主要是项目开源的时候须要用到。若是你想写一个开源软件,目录该如何组织,能够参考这篇文章。
下面,再简单讲一下我对这些目录的理解和我的要求吧。
这个我以为是每一个项目都应该有的一个文件,目的是能简要描述该项目的信息,让读者快速了解这个项目。
它须要说明如下几个事项:
我以为有以上几点是比较好的一个README
。在软件开发初期,因为开发过程当中以上内容可能不明确或者发生变化,并非必定要在一开始就将全部信息都补全。可是在项目完结的时候,是须要撰写这样的一个文档的。
能够参考Redis源码中Readme的写法,这里面简洁可是清晰的描述了Redis功能和源码结构。
通常来讲,用setup.py
来管理代码的打包、安装、部署问题。业界标准的写法是用Python流行的打包工具setuptools来管理这些事情。这种方式广泛应用于开源项目中。不过这里的核心思想不是用标准化的工具来解决这些问题,而是说,一个项目必定要有一个安装部署工具,能快速便捷的在一台新机器上将环境装好、代码部署好和将程序运行起来。
这个我是踩过坑的。
我刚开始接触Python写项目的时候,安装环境、部署代码、运行程序这个过程全是手动完成,遇到过如下问题:
setup.py
能够将这些事情自动化起来,提升效率、减小出错的几率。"复杂的东西自动化,能自动化的东西必定要自动化。"是一个很是好的习惯。
setuptools的文档比较庞大,刚接触的话,可能不太好找到切入点。学习技术的方式就是看他人是怎么用的,能够参考一下Python的一个Web框架,flask是如何写的: setup.py
固然,简单点本身写个安装脚本(deploy.sh
)替代setup.py
也何尝不可。
这个文件存在的目的是:
setup.py
安装依赖时漏掉软件包。
这个文件的格式是每一行包含一个包依赖的说明,一般是flask>=0.10
这种格式,要求是这个格式能被pip
识别,这样就能够简单的经过 pip install -r requirements.txt
来把全部Python包依赖都装好了。具体格式说明: 点这里。
conf.py
放在源码目录下,而是放在docs/
目录下。
不少项目对配置文件的使用作法是:
import conf
这种形式来在代码中使用配置。
这种作法我不太赞同:
conf.py
这个文件。
因此,我认为配置的使用,更好的方式是,
可以佐证这个思想的是,用过nginx和mysql的同窗都知道,nginx、mysql这些程序均可以自由的指定用户配置。
因此,不该当在代码中直接import conf
来使用配置文件。上面目录结构中的conf.py
,是给出的一个配置样例,不是在写死在程序中直接引用的配置文件。能够经过给main.py
启动参数指定配置路径的方式来让程序读取配置内容。固然,这里的conf.py
你能够换个相似的名字,好比settings.py
。或者你也可使用其余格式的内容来编写配置文件,好比settings.yaml
之类的。
实例:文件结构和不一样的文件目录的相互调用!
main.py:
atm.py:其中...bin/atm.py调用...core/main.py内的函数。
做业需求:
模拟实现一个ATM + 购物商城程序
示例代码 https://github.com/triaquae/py3_training/tree/master/atm
简易流程图:https://www.processon.com/view/link/589eb841e4b0999184934329
本人完成做业提交gitee.com
https://gitee.com/meijinmeng/Atm-Shopping
master 基础版
1stage 升级版