叠加装饰器与迭代器

Posted xy-han

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了叠加装饰器与迭代器相关的知识,希望对你有一定的参考价值。

一、叠加装饰器

叠加装饰器的定义

在同一个被装饰对象中,添加多个装饰器并执行

每一个新的功能都应该被放到一个新的装饰器,否则代码冗余,可扩展性差。

叠加装饰器:
装饰的顺序:由下到上装饰

执行的顺序:由上往下

注意:无论inner中出现任何判断最后都要返回“调用后的被装饰对象”。

‘‘‘
叠加装饰器:
    在同一个被装饰对象中,添加多个装饰器,并执行。
    @装饰1
    @装饰2
    @装饰3
    def 被装饰对象():
        pass

    注意: 装饰器在调用被装饰对象时才会执行添加的功能。

    - 叠加装饰器:
        - 装饰的顺序: 由下到上装饰
        - 执行的顺序: 由上往下

    注意: 无论inner中出现任何判断,最后都要返回“调用后的被装饰对象” func(*args, **kwargs)

‘‘‘

# def wrapper(func):
#     def inner(*args, **kwargs):
#         # 注册
#         res = func(*args, **kwargs)
#         # 登录
#         return res
#
#     return inner


# 需求: 为被装饰对象,添加统计时间 与 登录认证功能
import time

user_info = {
    user: None
}


# 登录功能
def login():
    # 判断用户没有登录时,执行
    # 登录功能
    # global user
    username = input(请输入账号: ).strip()
    password = input(请输入密码: ).strip()
    with open(user.txt, r, encoding=utf-8) as f:
        for line in f:
            print(line)
            name, pwd = line.strip(
).split(:)  # [tank, 123]

    if username == name and password == pwd:
        print(登录成功!)
        user_info[user] = username
        return True
    else:
        print(登录失败!)
        return False


# 登录认证装饰器
def login_auth(func):  # func---》 download_movie
    def inner1(*args, **kwargs):

        ‘‘‘
        注意: 无论inner中出现任何判断,
        最后都要返回“调用后的被装饰对象” func(*args, **kwargs)
        ‘‘‘

        # 登录认证
        if user_info.get(user):
            # res = download_movie(*args, **kwargs)
            res = func(*args, **kwargs)
            return res

        else:
            flag = login()
            # 添加用户是否登录判断
            if flag:
                res = func(*args, **kwargs)
                return res

            else:

                login()
                return func(*args, **kwargs)

    return inner1


# 统计时间装饰器
def time_record(func):
    def inner2(*args, **kwargs):
        print(开始统计...)
        start_time = time.time()
        res = func(*args, **kwargs)
        end_time = time.time()
        print(f消耗时间为: {end_time - start_time})
        return res
    return inner2


# 下载电影功能
‘‘‘
    - 叠加装饰器:
        - 装饰的顺序: 由下到上装饰
        - 执行的顺序: 由上往下
‘‘‘
@time_record  # inner2 = time_record(inner1地址)
@login_auth  # inner1 = login_auth(download_movie)
def download_movie():
    print(正在下载电影...)
    time.sleep(2)
    print(下载电影完成...)
    return GTWZ.mp4


# login()
# 执行的顺序: 先执行time_record功能,再执行login_auth功能
# 统计登录时间 + 下载时间
# download_movie()


# 装饰顺序
# @login_auth  # inner1 = login_auth(inner2)
# @time_record  # inner2 = time_record(download_movie)
# def download_movie():
#     print(‘正在下载电影...‘)
#     time.sleep(2)
#     print(‘下载电影完成...‘)
#     return ‘GTWZ.mp4‘


# 执行顺序:
# 先执行login_auth, 再执行time_record
# 只统计下载电影的时间
# login()  # 先调用登录,模拟用户已登录
download_movie()

叠加装饰器模板

def wrapper1(func):
    def inner1(*args, **kwargs):
        print(1---start)
        # 被裝飾對象在調用時,如果還有其他裝飾器,會先執行其他裝飾器中的inner
        # inner2
        res = func(*args, **kwargs)
        print(1---end)
        return res
    return inner1


def wrapper2(func):
    def inner2(*args, **kwargs):
        print(2---start)

        res = func(*args, **kwargs)
        print(2---end)
        return res
    return inner2


def wrapper3(func):
    def inner3(*args, **kwargs):
        print(3---start)
        res = func(*args, **kwargs)
        print(3---end)
        return res
    return inner3

‘‘‘
叠加裝飾器的裝飾順序與執行順序:
    - 裝飾順序: 调用wrapper装饰器拿到返回值inner
        由下往上裝飾
        
    - 執行順序: 调用装饰过后的返回值inner
        由上往下執行
‘‘‘


@wrapper1  # index《---inner1 = wrapper1(inner2)
@wrapper2  # inner2 = wrapper2(inner3)
@wrapper3  # inner3 = wrapper3(index)
def index():  # 被裝飾對象   # inner1 ---》
    print(from index...)


# 正在装饰
# inner3 = wrapper3(index)
# inner2 = wrapper2(inner3)
# inner1 = wrapper1(inner2)


‘‘‘
inner1()
inner2()
inner3()
index()
‘‘‘
index()  # 此处执行 # inner1() --> inner2() ---> inner3()

 

无参装饰器:装饰被装饰对象时,没有传参数的装饰器

有参数装饰器:装饰被装饰对象时,有传参数的装饰器,如:wrapper(参数)

# 无参装饰器: 装饰在被装饰对象时,没有传参数的装饰器。
‘‘‘
# 以下是无参装饰器
@wrapper1  # inner1 = wrapper1(inner2)
@wrapper2  # inner2 = wrapper2(inner3)
@wrapper3
‘‘‘

# 有参装饰器: 在某些时候,我们需要给用户的权限进行分类
‘‘‘
# 以下是有参装饰器
@wrapper1(参数1)  # inner1 = wrapper1(inner2)
@wrapper2(参数2)  # inner2 = wrapper2(inner3)
@wrapper3(参数3)
‘‘‘


# 有参装饰器
def user_auth(user_role):  # ‘SVIP‘
    def wrapper(func):
        def inner(*args, **kwargs):
            if user_role == SVIP:
                print(超级用户)
                # 添加超级用户的功能
                res = func(*args, **kwargs)
                return res
            elif user_role == 普通用户:
                print(普通用户)
                # 添加普通用户的功能
                res = func(*args, **kwargs)
                return res

        return inner
    return wrapper


# 被装饰对象
# @user_auth(‘SVIP‘)
#wrapper = user_auth(‘普通用户‘)
#@wrapper
@user_auth(SVIP)  # wrapper = user_auth(‘普通用户‘)
# @wrapper  #<--- 返回结果(wrapper) <---- user_auth()
def index():
    pass
index()

wraps: 
是一个修复工具,修复的是被装饰对象的空间。
###from functools import wraps

‘‘‘
wraps: (了解)
    是一个修复工具,修复的是被装饰对象的空间。
    from functools import wraps

‘‘‘
from functools import wraps


def wrapper(func):

    @wraps(func)  # 修改名称空间: inner ---》 func
    def inner(*args, **kwargs):
        ‘‘‘
        此处是装饰器的注释
        :param func:
        :return:
        ‘‘‘
        res = func(*args, **kwargs)
        return res
    return inner  # ---》 func


@wrapper
def index():
    ‘‘‘
    此处是index函数的注释
    :return:
    ‘‘‘
    pass


print(index)  # 函数对象

# 函数对象.__doc__: 查看函数内部的注释
print(index.__doc__)  # inner.__doc__

二、迭代器

迭代器是迭代取值的工具

迭代:迭代指的是重复迭代,每一次迭代都是基于上一次的结果而来

如果想要知道Python中迭代器是什么,必须先要知道什么是可迭代对象。

可迭代对象:所有序列类型:str,list, tuple, dict,set,f

凡是内部有__iter__()f方法都是可迭代类型,如:list__iter__()

获取迭代器:

通过可迭代对象.__iter__()得到的返回值就是‘迭代器对象’

 

迭代器是迭代取值的工具,作用就是迭代取值

如何取值:

迭代器对象.__next__()   #每执行一次就会取出一个对象
list1 = [1, 2, 3, 4]
iter_list1 = list1.__iter__()   #返回迭代器对象
print(iter_list1.__next__())    #每执行一次就会取出一个对象
print(iter_list1.__next__())
print(iter_list1.__next__())
print(iter_list1.__next__())
print(iter_list1.__next__())   #当可迭代对象内部没有对象时再取就会报错

结果:
1
2
3
4
  File "/Users/tophan/python练习/day12/迭代器.py", line 7, in <module>
    print(iter_list1.__next__())
StopIteration

迭代器对象的优点:

1、不依赖索引迭代取值

2、节省空间

迭代器对象缺点:

1、取指定的某个值麻烦

2、每次取值都要从第一个值开始,无法通过索引取值。

#文件即是可迭代对象,也是迭代器对象,因为文件从读取出来就是迭代器对象

***可迭代对象不一定是迭代器对象

迭代器对象一定是可迭代对象

# x = 10
# while True:
#     print(x)

#
# list1 = [1, 2, 3, 4]  # 1, 2, 3, 4
# n = 0
# while n < len(list1):
#     print(list1[n])
#     n += 1


# 以下都是可迭代对象
‘‘‘
str1 = ‘hello tank!‘
str1.__iter__()
list1 = [1, 2, 3]  # list([1, 2, 3])
list1.__iter__()
set.__iter__()
dict.__iter__()
tuple.__iter__()
open(‘a.txt‘).__iter__()
‘‘‘


# str1 = ‘靓仔靓女‘

# iter_str1 = str1.__iter__()
# print(iter_str1)  # iterator指的是迭代器对象   # iter_str1 ---> 靓仔,靓女!
# print(iter_str1.__next__())
# print(iter_str1.__next__())
# print(iter_str1.__next__())
# print(iter_str1.__next__())

# 因为迭代器中的值已经取完了
# print(iter_str1.__next__())  # 报错,StopIteration


dict1 = {age: 17, name: tank}
iter_dict1 = dict1.__iter__()

print(iter_dict1.__next__())
print(iter_dict1.__next__())
# print(iter_dict1.__next__())

 补充:


不依赖索引的取值方式
tuple1 = (‘tank‘, ‘jason鸡哥‘, ‘sean‘, ‘饼哥‘)

# 获取迭代器对象: iter_list1
iter_tuple1 = tuple1.__iter__()

while True:
# 补充: try: 捕获异常
try:
print(iter_tuple1.__next__()) # 报错

# 立即触发此处代码 StopIteration
except StopIteration:
break

 

for 循坏内部原理:

for 循坏在工作时,首先会调用可迭代对象goods内置的_iter_方法拿到一个迭代器对象,
然后再调用该迭代器对象的__next__方法将取到的值赋给item,执行循坏体,周而复始,

直到捕捉到Stopliteration异常,结束迭代。

 

 

 

 

以上是关于叠加装饰器与迭代器的主要内容,如果未能解决你的问题,请参考以下文章

Python 迭代器与生成器及装饰器

装饰器,迭代器与生成器

python基础-函数之装饰器迭代器与生成器

叠加装饰器迭代器

第十三天 叠加多个装饰器 迭代器 生成器

Day4 闭包装饰器decorator迭代器与生成器面向过程编程三元表达式列表解析与生成器表达式序列化与反序列化