一. 经典的两层装饰器,也是标准装饰器
案例
import time def outter1(func): def wrapper(*args, **kwargs): start = time.time() res = func(*args, **kwargs) stop = time.time() print(stop - start) return res return wrapper # @函数的内存地址1(1,2,3,4,5) # 函数的内存地址(index) def index(x, y): print('index===>', x, y) @outter1 def home(name): print('home====>', name)
引出两个点:
1、可以通过闭包的方式为函数体传参,可以包一层,也可以包两层
2、@后跟的必须是一个函数的内存地址
@函数的内存地址(1,2,3) 是可以的,但是前提是调用函数"函数的内存地址(1,2,3)"的
返回值必须是一个函数的内存地址
三层有参装饰器
第一阶
def outter(func): def wrapper(*args, **kwargs): inp_name=input("please input your name: ").strip() inp_pwd=input("please input your password: ").strip() with open('user.db',mode='rt',encoding='utf-8') as f: for line in f: name_db,pwd_db=line.strip(' ').split(':') if inp_name == name_db and inp_pwd == pwd_db: print('login successful') res = func(*args, **kwargs) return res else: print("账号或密码错误") return wrapper @outter def index(x, y): print('index===>', x, y) index(1, 2)
第二阶
获取认证信息途径有
1. ldap
2. mysql
3. file
...
def outter2(mode): def outter(func): def wrapper(*args, **kwargs): inp_name=input("please input your name: ").strip() inp_pwd=input("please input your password: ").strip() if mode == "file": print('认证来源=====>file') with open('user.db',mode='rt',encoding='utf-8') as f: for line in f: name_db,pwd_db=line.strip(' ').split(':') if inp_name == name_db and inp_pwd == pwd_db: print('login successful') res = func(*args, **kwargs) return res else: print("账号或密码错误") elif mode == "ldap": print('认证来源=====>ldap') elif mode == "mysql": print('认证来源=====>mysql') else: print("未知的认证来源") return wrapper return outter outter=outter2(mode="mysql") @outter # index=outter(index) ==>index=wrapper def index(x, y): print('index===>', x, y) index(1, 2) # wrapper(1,2)
第三阶(完美)
def outter2(mode): def outter(func): def wrapper(*args, **kwargs): inp_name=input("please input your name: ").strip() inp_pwd=input("please input your password: ").strip() if mode == "file": print('认证来源=====>file') with open('user.db', mode='rt', encoding='utf-8') as f: for line in f: name_db,pwd_db=line.strip(' ').split(':') if inp_name == name_db and inp_pwd == pwd_db: print('login successful') res = func(*args, **kwargs) return res else: print("账号或密码错误") elif mode == "ldap": print('认证来源=====>ldap') elif mode == "mysql": print('认证来源=====>mysql') else: print("未知的认证来源") return wrapper return outter @outter2(mode="mysql") # index=outter(index) ==>index=wrapper def index(x, y): print('index===>', x, y) index(1, 2) # wrapper(1,2)
二. 迭代器
简述:
迭代是一个重复的过程,每一次重复都是基于上一次的结果而来的
注意:迭代不是单纯的重复
迭代器是一种迭代取值的工具,这种取值方式是通用,不依赖于索引
str ===》索引 list ===》索引 tuple ===》索引 t = (1111, 222, 333, 444, 555, 666) i = 0 while i < len(t): print(t[i]) i += 1 dict ===》key set ===》既没有key也没有索引 f文件对象==》既没有key也没有索引
python为上述类型都内置了__iter__方法
例:
s = "hello" ll = [111, 222, 333] t = (1111, 222, 333, 444, 555, 666) d = {"k1": 111, "k2": 222, "k3": 3333} s1 = {'a', 'b', 'c'} f = open(r'user.db', mode='rt', encoding='utf-8') f.close()
操作方法
调用__iter__方法得到的返回值就是对应的迭代器
res = d.__iter__() # res=iter(d) print(res) # res是迭代器 a = res.__next__() # a=next(res) b = res.__next__() # b=next(res) c = res.__next__() # c=next(res) d = res.__next__() # StopIteration print(c) d = {"k1": 111, "k2": 222, "k3": 3333} iter_d = iter(d) while True: try: print(next(iter_d)) except StopIteration: break
迭代对象和迭代器对象区分
迭代的对象:有__iter__内置方法的对象都是可迭代的对象,str、list、tuple、dict、set、文件对象
ps:可迭代对象.__iter__()返回的是迭代器对象
迭代器对象:
1、有__next__方法
2、有__iter__方法,调用迭代器的__iter__方法得到的就是迭代器自己
ps:迭代器对象之所内置__iter__方法是为了符合for循环第一个工作步骤
例:
f = open(r'user.db', mode='rt', encoding='utf-8') line=f.__next__() print(line) line=f.__next__() print(line) for line in f: print(line) f.close() line=f.__next__() # 报错
叠加多个可迭代对象, 还是本身, 没有改变性质
d = {"k1": 111, "k2": 222, "k3": 3333} res=d.__iter__() print(res) print(res.__iter__()) print(res.__iter__() is res) print(res.__iter__().__iter__().__iter__() is res)
二、for循环的工作原理=》迭代器循环
d = {"k1": 111, "k2": 222, "k3": 3333} for k in d: print(k)
解释:
for循环的工作步骤
1、调用in后的对象的__iter__方法,得到对应的迭代器
2、k=next(迭代器),然后执行一次循环
3、循环往复,知道把迭代器的值取干净了,抛出异常,for循环会自动捕捉异常,结束循环
迭代器总结:
优点
1、不依赖索引,是一种通用的取值方式
2、节省内存
d = {"k1": 111, "k2": 222, "k3": 3333} iter_d=iter(d) next(iter_d)
缺点:
1、不能取指定位置的值
2、不能预估值的个数,无法统计长度
ll = [111, 222, 333] print(ll[2]) iter_ll=iter(ll) next(iter_ll) next(iter_ll) print(next(iter_ll))