装饰器 迭代器

装饰器

有参装饰器的实现

了解无参装饰器的实现原理后,我们可以再实现一个用来为被装饰对象添加认证功能的装饰器,实现的基本形式如下

def deco(func):
    def wrapper(*args, **kwargs):
        #编写基于文件的认证,认证通过则执行res=func(*args, **kwargs),并返回res
    return wrapper

如果我们想提供多种不同的认证方式以供选择,单从wrapper函数的实现角度改写如下

def deco(func):
    def wrapper(*args, **kwargs):
        if driver == 'file':
            print('基于文件认证通过')
            res = func(*args, **kwargs)
            return res
        elif driver == 'mysql':
            print('基于数据认证通过')
            res = func(*args, **kwargs)
            return res
        print('...')
    return wrapper

函数wrapper需要一个driver参数,而函数deco与wrapper的参数都有其特定的功能,不能用来接受其他类别的参数,可以在deco的外部再包一层函数auth,用来专门接受额外的参数,这样便保证了在auth函数内无论多少层都可以引用到

def auth(driver):
    def deco(func):
        def wrapper(*args, **kwargs):
            if driver == 'file':
                print('基于文件认证通过')
                res = func(*args, **kwargs)
                return res
            elif driver == 'mysql':
                print('基于数据认证通过')
                res = func(*args, **kwargs)
                return res
        print('...')
        return wrapper
    return deco


@auth(driver='aaa')#这里因为我们传入的参数没有
#下面为该语法糖最后代表的内容
#--->@和auth(driver='aaa')--->而auth(driver='aaa')相当于是调用函数auth得到结果为deco函数的内存地址,即此时这里为@deco,这里我们也可以将其分开为@和deco--->而@的作用就是相当于将被装饰对象的函数名当作参数传入该函数,所以现在就为deco(index),而该函数的结果为wrapper,所以这里我们可以写为wrapper=deco(index),即wrapper=wrapper  --->所以最后我们调用的函数其实是wrapper,但是装饰器的原则之一为不修改被装饰对象的调用方式,所以我们可以将wrapper函数对应的内存地址定义一个变量index=wrapper。
def index():
    print('from index')
    
index()
#输出结果为
...

可以使用help(函数名)来查看函数的文档注释,本质就是查看函数的__doc__属性,但对于被装饰之后的函数,查看文档注释

import time
def timer(func):
    def wrapper(*args, **kwargs):
        start_time = time.time()
        res = func(*args, **kwargs)
        end_time = time.time()
        print('run time is %s'%(end_time - start_time))
        return res
    return wrapper

@timer
def home(name):
    '''
    home page function
    :param name:str
    :return:None
    '''
    time.sleep(5)
    print('Welcome to the home pae', name)
print(help(home))
#输出结果为
Help on function wrapper in module __main__:

wrapper(*args, **kwargs)

None

Process finished with exit code 0

在被装饰之后home=wrapper,查看home.__name__也可以发现home的函数名确实是wrapper,想要保留原函数的文档和函数名属性,需要修正装饰器

def timer(func):
    def wrapper(*args,**kwargs):
        start_time=time.time()
        res=func(*args,**kwargs)
        stop_time=time.time()
        print('run time is %s' %(stop_time-start_time))
        return res
    wrapper.__doc__=func.__doc__
    wrapper.__name__=func.__name__
    return wrapper

按照上述方式来实现保留原函数属性过于麻烦,functools模块下提供一个装饰器wraps专门用来帮我们实现这件事,用法如下

from functools import wraps

def timer(func):
    @wraps(func)
    def wrapper(*args,**kwargs):
        start_time=time.time()
        res=func(*args,**kwargs)
        stop_time=time.time()
        print('run time is %s' %(stop_time-start_time))
        return res
    return wrapper

迭代器

迭代器
迭代的工具。

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

    迭代器:
        迭代器指的是迭代取值的工具,它可以迭代取值。

    - 如果想要知道python中迭代器是什么?必须先知道什么是可迭代对象?

    - 可迭代对象:  所有的序列类型: str, list, tuple, dict, set, f
        凡是内部有str.__iter__()方法的都是可迭代对象。

    - 获取迭代器:
        通过可迭代对象.__iter__(), 得到的返回值就是 “迭代器对象”。
        迭代器是迭代取值的工具,作用是迭代取值。

    - 如何迭代取值:
        迭代器对象.__next__()  # “每一次执行”,都会从迭代器对象中取出一个值


    - 总结: 可迭代对象 VS 迭代器对象:
        - 获取可迭代对象: 定义序列类型(str, list, set, tuple, dict, f)
            - 特点:
                内置有__iter__()

        - 获取迭代器对象: 通过可迭代对象调用.__iter__()得到返回值
            - 特点:
                内置有__next__()

    - 迭代器对象的优点:
        - 优点:
            1.不依赖于索引迭代取值。
            2.节省内存空间。

        - 缺点:
            1.取指定某个值麻烦
            2.每次取值都要从第一个值开始,无法同过索引取值。


    for循环原理
        语法:     for i in 可迭代对象:
        in: 可迭代对象 ----> 内部会自动调用.__iter__() ---> 迭代器对象
        for line in list1:
            # 迭代器对象.__next__()



    - 迭代器本质上是一个可迭代对象

    - 文件本质上既是迭代器对象,也是可迭代对象。

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

猜你喜欢

转载自www.cnblogs.com/a736659557/p/11892366.html