函数(五)——装饰器,迭代器

今日内容概要:

一、嵌套三层函数的装饰器(了解)

二、迭代器(掌握)

内容详解:

一、嵌套三层函数的装饰器

#分析
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('\n').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)
#示范二(完善):
# ldap
# mysql
# 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('\n').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('\n').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)

二、迭代器

1、迭代器

迭代是一个重复的过程,每一次重复都是基于上一次的结果而来的
 注意:迭代不是单纯的重复
迭代器是一种迭代取值的工具,这种取值方式是通用,不依赖于索引
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
2、可迭代的对象:有__iter__内置方法的对象都是可迭代的对象,str、list、tuple、dict、set、文件对象
ps:可迭代对象.__iter__()返回的是迭代器对象

3、迭代器对象:
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)

4、for循环的工作原理=》迭代器循环

for循环的工作步骤:
(1)调用in后的对象的__iter__方法,得到对应的迭代器
(2)k=next(迭代器),然后执行一次循环
(3)循环往复,直到把迭代器的值取干净了,抛出异常,for循环会自动捕捉异常,结束循环
d = {"k1": 111, "k2": 222, "k3": 3333}

for k in d:
    print(k)

5、总结迭代器:

优点:
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))

猜你喜欢

转载自www.cnblogs.com/guojieying/p/13179332.html