18、有参函数和迭代器以及生成器
一、有参函数
1.1、装饰器的目标,即偷梁换柱之后
1.原函数参数是什么样的,装饰器的参数就应该是什么样的
2.原函数返回值是什么样的,装饰器的返回值就应该是什么样的
3.原函数的属性是什么样的,装饰器的属性就行该是什么样的 # from functools import wraps
1.2、有参函数的使用
在无参函数的基础上设定有参函数
def auth(func,db_type): def wrapper(*args, **kwargs): # name=input('your name>>>: ').strip() pwd=input('your password>>>: ').strip() if db_type == 'file': print('基于文件的验证') if name == 'egon' and pwd == '123': res = func(*args, **kwargs) return res else: print('user or password error') elif db_type == 'mysql': print('基于mysql的验证') elif db_type == 'ldap': print('基于ldap的验证') else: print('不支持该db_type') return wrapper #在无参函数的基础上添加了判断条件,并且判断条件需要从其他函数里面调用 # @auth # 账号密码的来源是文件 def index(x,y): print('index->>%s:%s' %(x,y)) # @auth # 账号密码的来源是数据库 def home(name): print('home->>%s' %name) # @auth # 账号密码的来源是ldap def transfer(): print('transfer') index=auth(index,'file') #函数的启动 home=auth(home,'mysql') transfer=auth(transfer,'ldap') # index(1,2) #给函数赋值 # home('egon') # transfer()
1.3、对函数进行优化,修改函数体。添加新函数,值为条件。原函数后退一格,末尾加return 值为上一个内函数。
def auth(db_type): #新增函数,在无参函数的外围在逃一个函数,用来添加条件 函数内的值填为条件 def deco(func): #将所有函数进行后退一格 def wrapper(*args, **kwargs): name=input('your name>>>: ').strip() pwd=input('your password>>>: ').strip() if db_type == 'file': #添加的条件 print('基于文件的验证') if name == 'egon' and pwd == '123': res = func(*args, **kwargs) return res else: print('user or password error') elif db_type == 'mysql': print('基于mysql的验证') elif db_type == 'ldap': print('基于ldap的验证') else: print('不支持该db_type') return wrapper return deco #添加return 值为之前的函数 deco=auth(db_type='file') @deco # 账号密码的来源是文件 def index(x,y): print('index->>%s:%s' %(x,y)) deco=auth(db_type='mysql') @deco # 账号密码的来源是数据库 def home(name): print('home->>%s' %name) deco=auth(db_type='ldap') @deco # 账号密码的来源是ldap def transfer(): print('transfer') index(1,2) home('egon') transfer()
1.4、对函数进行优化,修改被装饰函数的启动项,@最后一层函数,内部条件为判断条件
def auth(db_type): # 插入新函数,值为参数 def deco(func): #后退一格 def wrapper(*args, **kwargs): name=input('your name>>>: ').strip() #函数体 pwd=input('your password>>>: ').strip() if db_type == 'file': #新增判断条件,即新增参数 print('基于文件的验证') if name == 'egon' and pwd == '123': res = func(*args, **kwargs) return res else: print('user or password error') elif db_type == 'mysql': print('基于mysql的验证') elif db_type == 'ldap': print('基于ldap的验证') else: print('不支持该db_type') return wrapper #return 由于缩进,导致原参数只能返回到局部。将原本需要输出的值返回全局,不改变原来的状态 值为前一个函数 return deco #将两个函数触发项进行合并 @auth(db_type='file') # @deco # index=deco(index) # index=wrapper def index(x, y): print('index->>%s:%s' % (x, y)) @auth(db_type='mysql') # @deco # home=deco(home) # home=wrapper def home(name): print('home->>%s' % name) @auth(db_type='ldap') # 账号密码的来源是ldap def transfer(): print('transfer') index(1,2) home('egon') transfer()
1.5、有参函数模板
def 有参装饰器(x,y,z): def outter(func): def wrapper(*args, **kwargs): res = func(*args, **kwargs) return res return wrapper return outter @有参装饰器(1,y=2,z=3) def 被装饰对象(): pass
二、迭代器
2.1、 什么是迭代器
迭代器指的是迭代取值的工具,迭代是一个重复的过程,每次重复是基于上一次重复的结果
2.2、为什么要有迭代器
迭代器使用来迭代取值的工具,涉及到循环的过程
可以使用的类型有:列表、字符串、元组、字典、集合、打开文件
while只能在有序的类型中使用,因此python需要一种任意类型都能使用取值的方式,即for的使用原理
2.3、怎么使用迭代器
2.3.1、使用__iter__的方式来使用迭代器
# 1、可迭代的对象:但凡内置有__iter__方法的都称之为可迭代的对象 # s1='' # # s1.__iter__()
2.3.2、使用——next——的方式的带迭代器对象
# 2、调用可迭代对象下的__iter__方法会将其转换成迭代器对象 d={'a':1,'b':2,'c':3} d_iterator=d.__iter__() #将列表d加入迭代器 # print(d_iterator) # print(d_iterator.__next__()) 输出迭代器的值 # print(d_iterator.__next__()) # print(d_iterator.__next__()) # print(d_iterator.__next__()) # 抛出异常StopIteration,迭代器里面无值
2.4、可迭代对象和迭代器对象的区别
可迭代对象:(可以转换成跌迭器的对象):内置有__iter__的对象
迭代器对象:同时存在__iter__以及——next——的对象
——next——会返回迭代器下一个值,而——iter——返回迭代器本身
2.5、可迭代对象和迭代器对象的范围
可迭代对象:列表、字符串、元组、字典、集合、文件对象
迭代器对象:文件对象
2.6、for循环的原理,即迭代器循环
for循环分为三步:
1.先使用迭代器d.__iter__()得到对象
2.使用迭代器对象__iter__()得到返回值,然后赋值给k
3.最后重复第二步,直到迭代器的值全部输出后报错
for k in d: print(k) with open('a.txt',mode='rt',encoding='utf-8') as f: for line in f: # f.__iter__() print(line) list('hello') #原理同for循环
2.7、迭代器的优缺点
优点:为所有类型都提供了一对一取值的方式
惰性计算:迭代器对象表示的是一个数据流,只有在调用next的时候才能计算出一个值,同一时刻内存中只存在一个值,因此可以存放无限大的数据流
缺点:除非取尽数据,否则无法算出迭代器的长度
只能取一个值,不能重新开始,除非取尽否则会一直停留在原地
若使用多个函数使用一个迭代器取值,只有一个能生效。
三、生成器
3.1、怎么自定义生成器
使用yield返回迭代器对象,不会像return一样退出,生成器就是迭代器
def func(): print('第一次') yield 1 print('第二次') yield 2 print('第三次') yield 3 print('第四次')
g=func()
print(g)
3.2、举例:
def my_range(start,stop,step=1): print('start...') while start < stop: yield start start+=step print('end....') g=my_range(1,5,2) # 1 3 print(next(g)) print(next(g)) print(next(g)) #需要使用next来执行下一次操作
3.3、多个装饰器的加载 (了解)
加载时从下到上进行加载,执行时从上到下开始执行
def deco1(func1): # func1 = wrapper2的内存地址 def wrapper1(*args,**kwargs): print('正在运行===>deco1.wrapper1') res1=func1(*args,**kwargs) return res1 return wrapper1 def deco2(func2): # func2 = wrapper3的内存地址 def wrapper2(*args,**kwargs): print('正在运行===>deco2.wrapper2') res2=func2(*args,**kwargs) return res2 return wrapper2 def deco3(x): def outter3(func3): # func3=被装饰对象index函数的内存地址 def wrapper3(*args,**kwargs): print('正在运行===>deco3.outter3.wrapper3') res3=func3(*args,**kwargs) return res3 return wrapper3 return outter3 # 加载顺序自下而上(了解) @deco1 # index=deco1(wrapper2的内存地址) ===> index=wrapper1的内存地址 @deco2 # index=deco2(wrapper3的内存地址) ===> index=wrapper2的内存地址 @deco3(111) # ===>@outter3===> index=outter3(index) ===> index=wrapper3的内存地址 def index(x,y): print('from index %s:%s' %(x,y)) # 执行顺序自上而下的,即wraper1-》wrapper2-》wrapper3 index(1,2) # wrapper1(1,2)