Day05:装饰器,三元表达式,函数的递归,匿名/内置函数,迭代器,模块,开发目录
上节课复习:
1.函数的对象
函数可以被当作数据取处理
2.函数嵌套
嵌套调用:在调用一个函数时,函数体代码又调用了其他函数
嵌套定义:在一个函数内部又定义了另一个函数
1 def foo() 2 def inner(): 3 pass 4 return inner #拿到inner的内存地址 5 f=foo() #foo全局变量可以通过返回的inner地址调用inner
3.名称空间与作用域
名称空间:存放名字与值的内存地址绑定关系的地方
x=1
x
内置名称空间
全局名称空间
局部名称空间
查找顺序:当前所在的位置往上依次查找
全局作用范围:全局存活,全局有效
1 def f1(): 2 def f1_inner1(): 3 def f1_inner2(): 4 pass 5 def f2(): 6 def f2_inner1(): 7 def f2_inner2(): 8 pass
局部作用范围:临时存活,局部有效
强调:作用域关系在函数定义阶段就已经固定死了,与调用关系无关
4.闭包函数
闭:封闭在函数内部,即定义在函数内部的函数
包:该内部包含对外部函数作用域名字的引用
1 x=1 2 def outter(): 3 x=111 4 def inner(): 5 print (x) 6 return inner 7 f=outter()
今日内容:
1.装饰器剩余(*****)
有参装饰器
2.三元表达式,列表生成式,字典生成式(*****)
3.函数的递归调用,二分法(*****)
4.匿名函数lambda+内置函数(*****)
5.迭代器(****)
6.模块的使用(*****)
7.软件开发的目录规范(*****)
一.装饰器
1.定义:器指的是工具,装饰指的是为被装饰的对象添加新功能
装饰器即使为被装饰对象添加新功能的工具
装饰器本身可以是任意可调用的对象
被装饰对象本身也可以是任意可调用的对象
2.开放封闭原则:
软件一旦上线以后,就应该对修改(源代码+调用方式)封闭,对扩展开放的
1.不修改被装饰对象的源代码
2.不修改被装饰对象的调用方式
3.如何实现
1 #原先的调用方式 2 import time 3 def index(): 4 print('welcom to index page') 5 time.sleep(1) 6 start=time.time() 7 index() 8 stop=time.time() 9 print ('run time is %s' %(stop - start))
输出:
welcom to index page
run time is 1.0005970001220703
1 import time 2 def index(): 3 print('welcom to index page') 4 time.sleep(1) 5 def wrapper(func): 6 start=time.time() 7 func() 8 stop=time.time() 9 print ('run time is %s' %(stop - start)) 10 11 wrapper(index)
输出:
welcom to index page
run time is 1.000910758972168
1 import time 2 def index(): 3 print('welcom to index page') 4 time.sleep(1) 5 def outter(func): 6 def wrapper(): 7 start=time.time() 8 func() 9 stop=time.time() 10 print ('run time is %s' %(stop - start)) 11 return wrapper 12 index=outter(index) 13 index()
输出:
welcom to index page
run time is 1.0008034706115723
1 #加了装饰器,目的是不改变原来的调用方式,对使用者是透明的 2 import time 3 def index(): 4 print('welcom to index page') 5 time.sleep(1) 6 def outter(func): 7 def wrapper(*args,**kwargs): 8 start=time.time() 9 res=func(*args,**kwargs) 10 stop=time.time() 11 print ('run time is %s' %(stop - start)) 12 return res 13 return wrapper 14 index=outter(index) 15 index() #wrapper() 为实际调用函数,需模拟原先的内部逻辑
输出:
welcom to index page
run time is 1.0013582706451416
1 #加了装饰器,目的是不改变原来的调用方式,对使用者是透明的 2 import time 3 def index(): 4 print('welcom to index page') 5 time.sleep(1) 6 def home(name): 7 print('welcom to home page') 8 time.sleep(2) 9 def outter(func): 10 def wrapper(*args,**kwargs): 11 start=time.time() 12 res=func(*args,**kwargs) 13 stop=time.time() 14 print ('run time is %s' %(stop - start)) 15 return res 16 return wrapper 17 index=outter(index) 18 home=outter(home) 19 index() #wrapper() 为实际调用函数,需模拟原先的内部逻辑 20 home('andy') #wrapper('andy')
welcom to index page
run time is 1.0008716583251953
welcom to home page
run time is 2.0003538131713867
#加了装饰器,目的是不改变原来的调用方式,对使用者是透明的 import time def timmer(func): 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 @timmer #index=timer(index) def index(): print('welcom to index page') time.sleep(1) @timmer #home=timer(home) def home(name): print('welcom to home page') time.sleep(2) return 123 index() #wrapper() 为实际调用函数,需模拟原先的内部逻辑 res=home('andy') #wrapper('andy')
输出:
welcom to index page
run time is 1.0023157596588135
welcom to home page
run time is 2.000333309173584
1 #模板 2 def outter(func): 3 def inner(*args,**kwargs): 4 res=func(*args,**kwargs) 5 return res 6 return res
输出:
1 #认证功能装饰器实现 2 import time 3 4 current_userinfo={'user':None} 5 def outter(func): # func为被装饰对象 6 def wrapper(*args,**kwargs): 7 if current_userinfo['user']: #判断是否已登陆 8 return func(*args,**kwargs) 9 else: 10 user=input('please input username:').strip() 11 pwd=input('please input password:').strip() 12 if user == 'andy' and pwd =='123': 13 print('login successfully') 14 #保存登陆状态 15 current_userinfo['user']=user 16 res=func(*args,**kwargs) 17 return res 18 else: 19 print ('user or password wrong') 20 return wrapper 21 @outter #index=outter(index) 22 def index(): 23 print('welcom to index page') 24 time.sleep(1) 25 @outter #home=outter(home) 26 def home(name): 27 print('welcom to home page') 28 time.sleep(2) 29 return 123 30 31 index() #wrapper() 为实际调用函数,需模拟原先的内部逻辑 32 res=home('andy') #wrapper('andy')
输出:
please input username:andy
please input password:123
login successfully
welcom to index page
welcom to home page
1 #添加多个装饰器 2 import time 3 current_userinfo={'user':None} 4 def timmer(func): #func=wrapper1 5 def wrapper2(*args,**kwargs): 6 print('wrapper2 run...') 7 start=time.time() 8 res=func(*args,**kwargs) #调到outter内的wrapper1 9 stop=time.time() 10 print ('run time is %s' %(stop - start)) 11 return res 12 return wrapper2 13 14 def outter(func): # func=最原始的index 15 def wrapper1(*args,**kwargs): 16 print('wrapper1 run...') 17 if current_userinfo['user']: #判断是否已登陆 18 return func(*args,**kwargs) 19 else: 20 user=input('please input username:').strip() 21 pwd=input('please input password:').strip() 22 if user == 'andy' and pwd =='123': 23 print('login successfully') 24 #保存登陆状态 25 current_userinfo['user']=user 26 res=func(*args,**kwargs) #调用最原始的index 27 return res 28 else: 29 print ('user or password wrong') 30 return wrapper1 31 @timmer #index=timmer(wrapper1),将下方返回的wrapper1传入 32 @outter #outter(最原始的index) ==> wrapper1=outter(最原始的index) 33 def index(): 34 print('welcom to index page') 35 time.sleep(1) 36 index() #index==>wrapper2
输出:
wrapper2 run...
wrapper1 run...
please input username:andy
please input password:123
login successfully
welcom to index page
run time is 8.713418006896973
1 #添加多个装饰器 2 import time 3 current_userinfo={'user':None} 4 def timmer(func): #func=wrapper1 5 def wrapper2(*args,**kwargs): 6 print('wrapper2 run...') 7 start=time.time() 8 res=func(*args,**kwargs) #调到outter内的wrapper1 9 stop=time.time() 10 print ('run time is %s' %(stop - start)) 11 return res 12 return wrapper2 13 14 def outter(func): # func=最原始的index 15 def wrapper1(*args,**kwargs): 16 print('wrapper1 run...') 17 if current_userinfo['user']: #判断是否已登陆 18 return func(*args,**kwargs) 19 else: 20 user=input('please input username:').strip() 21 pwd=input('please input password:').strip() 22 if user == 'andy' and pwd =='123': 23 print('login successfully') 24 #保存登陆状态 25 current_userinfo['user']=user 26 res=func(*args,**kwargs) #调用最原始的index 27 return res 28 else: 29 print ('user or password wrong') 30 return wrapper1 31 # 可以连续写多个装饰器,处于最顶层的装饰器先执行,解释语法自下而上,执行时则自上而下 32 @outter # 33 @timmer # 34 def index(): 35 print('welcom to index page') 36 time.sleep(1) 37 index() #index==>wrapper2
输出:
wrapper1 run...
please input username:andy
please input password:123
login successfully
wrapper2 run...
welcom to index page
run time is 1.0009920597076416
1 #有参装饰器 2 #认证功能装饰器实现 3 import time 4 5 current_userinfo={'user':None} 6 def auth(engine='file'): 7 def outter(func): # func为被装饰对象 8 def wrapper(*args,**kwargs): 9 if engine == 'file': 10 if current_userinfo['user']: #判断是否已登陆 11 return func(*args,**kwargs) 12 else: 13 user=input('please input username:').strip() 14 pwd=input('please input password:').strip() 15 if user == 'andy' and pwd =='123': 16 print('login successfully') 17 #保存登陆状态 18 current_userinfo['user']=user 19 res=func(*args,**kwargs) 20 return res 21 else: 22 print ('user or password wrong') 23 elif engine == 'mysql': 24 print ('mysql 的认证机制') 25 elif engine == 'ldap': 26 print ('ldap 的认证机制') 27 else: 28 print('不支持该engine') 29 return wrapper 30 return outter 31 @auth(engine='mysql') 32 #@outter #index=outter(index) #index=wrapper 33 def index(): 34 print('welcom to index page') 35 time.sleep(1) 36 @auth(engine='file') 37 def home(name): 38 print('welcom to home page') 39 time.sleep(2) 40 return 123 41 42 index() #wrapper() 为实际调用函数,需模拟原先的内部逻辑 43 res=home('andy') #wrapper('andy')
输出:
mysql 的认证机制
please input username:andy
please input password:123
login successfully
welcom to home page
1 #加了装饰器,目的是不改变原来的调用方式,对使用者是透明的 2 import time 3 from functools import wraps 4 5 def timmer(func): 6 @wraps(func) 7 def wrapper(*args,**kwargs): 8 start=time.time() 9 res=func(*args,**kwargs) 10 stop=time.time() 11 print ('run time is %s' %(stop - start)) 12 return res 13 #wrapper.__doc__=func.__doc__ 14 #wrapper.__name__=func.__name__ 15 return wrapper 16 @timmer #index=timer(index) 17 def index(): 18 """ 19 这是一个index函数 20 :return 21 """ 22 print('welcom to index page') 23 time.sleep(1) 24 return 123 25 print(help(index)) 26 #print(index.__name__)
输出:
Help on function index in module __main__:
index()
这是一个index函数
:return
None
1 #三元表达式 2 def max2(x,y): 3 if x>y: 4 return x 5 else: 6 return y 7 res=max2(1,2) 8 9 res=True if x>y else False 10 print (res) 11 12 #列表生成式 13 l=[] 14 for i in range(10): 15 l.append(i) 16 print(l) 17 18 l1=[i for i in range(10)] 19 print(l1) 20 21 #字典生成式 22 s={i:i for i in range(10) if i>3} 23 print (s) 24 25 26 info=[ 27 ['name','alex'], 28 ('age',18) 29 ['sex','male'] 30 ] 31 d={item[0]:item[1] for item in info} 32 print(d) 33 34 d={k.upper():v for k,v in d.items()} 35 print(d)
二.函数递归
函数递归调用,在调用一个函数的过程中又直接或间接地调用了自己称之为函数的递归调用
本质就是一个重复的过程,递归必须要满足两个阶段
1.回溯:一层一层地递归调用下去
2.递推:递归必须要有一个明确的结束条件,在满足该条件下终止递归,往回一层一层地结束调用
递归vs while循环
递归只需要把控住结束或进入递归的条件即可,至于循环次数无需考虑
1 #直接递归 2 def foo(n): 3 print('from foo',n) 4 foo(n+1) 5 foo(0) 6 7 #间接递归 8 def bar(): 9 print('from bat') 10 11 def foo(): 12 print('from foo') 13 bar() 14 foo()
1 def age(n): 2 if n==1: 3 return 18 4 return age(n-1) +2 5 6 print(age(5))
输出:26
1 l=[1,[2,[3,]]] 2 def tell(l): 3 for item in l: 4 if type(item) is not list: 5 print(item) 6 else: 7 #再次调用本身的逻辑,传入item 8 tell(item) 9 tell(l)
输出:
1
2
3
1 nums=[3,11,13,15,23,27,43,51,72,81,93,101] 2 #算法,就是高效解决某个具体问题的方法 3 #find_num=23 4 def binary_search(nums,find_num): 5 print(nums) 6 if len(nums) == 0: 7 print('not exists') 8 return 9 mid_index=len(nums) // 2 10 if find_num>nums[mid_index]: 11 nums=nums[mid_index+1:] 12 binary_search(nums,find_num) 13 elif find_num < nums[mid_index]: 14 nums=nums[:mid_index] 15 binary_search(nums,find_num) 16 else: 17 print('find it') 18 binary_search(nums,99) 19 binary_search(nums,3)
输出:
[3, 11, 13, 15, 23, 27, 43, 51, 72, 81, 93, 101]
[51, 72, 81, 93, 101]
[93, 101]
[93]
[]
not exists
[3, 11, 13, 15, 23, 27, 43, 51, 72, 81, 93, 101]
[3, 11, 13, 15, 23, 27]
[3, 11, 13]
[3]
find it
三.匿名函数
匿名函数lambda:只用一次以后不会再用了
(lambda x,y:x+y)(4,5)
输出:9
#原方法 salaries={ 'andy':1000, 'alex':2000, 'lily':400 } def func(k): return salaries[k] print(max(salaries,key=func)) #使用匿名函数 salaries={ 'andy':1000, 'alex':2000, 'lily':400 } print(max(salaries,key=lambda x:salaries[x]))
输出:alex
1 num=[3,1,4,9] 2 l=sorted(num) 3 print (l) 4 l=sorted(num,reverse=True) 5 print (l)
输出:
[1, 3, 4, 9]
[9, 4, 3, 1]
1 salaries={ 2 'andy':1000, 3 'alex':2000, 4 'lily':400 5 } 6 7 print(sorted(salaries,key=lambda x:salaries[x]))
输出:
['lily', 'andy', 'alex']
1 #了解map,reduce,filter 2 #map映射 3 names=['andy','alex','tom'] 4 res=map(lambda x:x+'_dsb',names) 5 print (list(res))
输出:
['andy_dsb', 'alex_dsb', 'tom_dsb']
1 #filter过滤 2 names=['andy_dsb', 'alex_dsb', 'tom_dsb'] 3 res=filter(lambda x:x.endswith('dsb'),names) 4 print (res) 5 for item in res: 6 print(item) 7 l=[name for name in names if name.endswith('dsb')] 8 print(l)
输出:
<filter object at 0x0000023BB55D6A58>
andy_dsb
alex_dsb
tom_dsb
['andy_dsb', 'alex_dsb', 'tom_dsb']
1 #reduce合并 2 from functools import reduce 3 l=['a','b','c','d','e'] 4 res=reduce(lambda x,y:x+y,l,'AAA') 5 print(res)
输出:
AAAabcde
1 from functools import reduce 2 l=['a','b','c','d','e'] 3 res=reduce(lambda x,y:x+y,l) 4 print(res)
输出:
abcde
四.模块
1.什么是模块
模块就是一系列功能的集合体,
模块分为三大类:
1.自定义模块
2.内置模块:time,sys
3.第三方的模块
模块的表现形式有
1.使用python编写的.py文件
2.已被编译为共享库或DLL的C或C++扩展
3.把一系列模块组织到一起的文件夹(注:文件夹下有一个__init__.py文件,该文件夹称之为包)
4.使用C编写并链接到python解释器的内置模块
2.为何要用模块
1.可以拿来内置或第三方的模块,然后直接使用,这种拿来主义,会极大地提高开发效率
2.将程序中公用的一些功能组织到一个文件中,然后程序个部分功能可以重用该文件的功能
优点是减少代码冗余,增强程序的组织结构性和可维护性
3.如何用模块
一个py文件就是一个模块
4.首次导入模块会发生三件事:
1.创建一个模块spam.py的名称空间
2.执行模块对应的spam.py,将产生的名字丢到模块的名称空间
3.在当前执行的名称空间中拿到一个名字spam,该名字就是指向模块spam.py的名称空间的内存地址
import spam #spam=spam.py
import spam #后续的导入执行引用之前导入的结果spam=spam.py名称空间的内存地址
print (spam.money)
两种导入方式的优缺点:
from import vs import
相同点:函数的作用域关系在定义阶段就规定死了,与调用位置无关
from import
优点:可以不用加前缀而直接引用名字,更简洁
缺点:容易与当前执行文件中的名字冲突
import
优点:指名道姓跟某一个名称空间要名字,肯定不会与当前名称空间的名字相冲突
缺点:必须加上前缀
#一个python文件有两种用途
1.可以执行: __name__ =='__main__'
2.可以被当作模块导入:__name__=='模块名'
模块的搜索优先级:
1.内存
2.内置的模块
3.sys.path
1 import sys 2 print(sys.path)