zoukankan      html  css  js  c++  java
  • day4_python-之装饰器、迭代器、生成器

    一、装饰器

    1、为何要用装饰器

    #开放封闭原则:对修改封闭,对扩展开放

    2、 什么是装饰器

    装饰器他人的器具,本身可以是任意可调用对象,被装饰者也可以是任意可调用对象。
    强调装饰器的原则:1 不修改被装饰对象的源代码 2 不修改被装饰对象的调用方式
    装饰器的目标:在遵循1和2的前提下,为被装饰对象添加上新功能
    import time
    
    
    def index():
        time.sleep(3)
        print('welcome to index')
    
    
    # index()
    
    def wrapper(func):
        start_time = time.time()
        func()
        stop_time = time.time()
        print('run time is %s' % (stop_time - start_time))
    
    
    wrapper(index)
    
    
    # ================闭包实现=============================
    import time
    
    
    def index():
        time.sleep(3)
        print('welcome to index')
    
    
    def timmer():
        func = index  # 这么写严格收到层级限制了,内部的函数无法调取,需要return返回值
    
        def wrapper():  # 注意这里,func已经定义了等于index,就不需要写默认参数了
            start_time = time.time()
            func()
            stop_time = time.time()
            print('run time is %s' % (stop_time - start_time))
    
        return wrapper
    
    
    # wrapper=timmer()       #运行timmer,得到的结果是wrapper,并且把值赋给了wrapper
    # wrapper()
    
    index = timmer()  # 如上,既然可以把timmer运行的返回值赋值给warpper,那么同理也可以赋值给index
    index()
    
    ####这么写没有修改源代码,也没有修改调用方式,也加上的新功能。实现了装饰器
    ####这么写其实是有问题的,如果又来了一个函数。这种闭包就无法实现了。解决方法如下
    # ==============================================
    
    import time
    
    
    def index():
        time.sleep(3)
        print('welcome to index')
    
    
    def home():
        time.sleep(2)
        print('welcome to home page')
    
    
    # index()
    def timmer(func):
        # func=index
        def wrapper():  # 注意这里,func已经定义了等于index,就不需要写默认参数了
            start_time = time.time()
            func()
            stop_time = time.time()
            print('run time is %s' % (stop_time - start_time))
    
        return wrapper
    
    
    index = timmer(index)  # 给func一个index的值,最后返回的值是wrapper,我可以把它赋值给index,home同理
    home = timmer(home)
    index()
    home()
    
    # =================装饰器=======================
    
    
    
    
    import time
    
    
    
    def timmer(func):
        # func=index
        def wrapper():
            start = time.time()
            func()
            stop = time.time()
            print('run time is %s' % (stop - start))
    
        return wrapper
    
    
    @timmer  # index=timmer(index)   自上而下运行,代表调用timmer 并且给timmer传值为index
    def index():
        time.sleep(3)
        print('welcome to index')
    
    
    @timmer # home=timmer(home)
    def home():
        time.sleep(2)
        print('welcome to home page')
    
    index()
    home()
    
    
    
    # =================被装饰器是有参函数=======================
    
    
    import time
    
    
    
    def timmer(func):
        # func=index
        def wrapper(name):
            start = time.time()
            func(name)
            stop = time.time()
            print('run time is %s' % (stop - start))
    
        return wrapper
    
    
    @timmer  # home=timmer(home)
    def home(name):
        time.sleep(2)
        print('welcome %s home ' % (home))
    
    
    home('egon')
    
    
    # ===========有参和无参混合用=======================
    import time
    
    
    
    def timmer(func):
        # func=index
        def wrapper(*args, **kwargs):  # 闭包函数适应有参无参,各种* 传参的方式
            start = time.time()
            func(*args, **kwargs)
            stop = time.time()
            print('run time is %s' % (stop - start))
    
        return wrapper
    
    
    @timmer  # index=timmer(index)   自上而下运行,代表调用timmer 并且给timmer传值为index
    def index():
        time.sleep(3)
        print('welcome to index')
    
    
    @timmer  # home=timmer(home)
    def home(name):
        time.sleep(2)
        print('welcome %s to home ' % (name))
    
    
    index()
    home('agon')
    View Code
    import time
    
    
    def timmer(func):
        def wrapper(*args, **kwargs):
            start = time.time()
            res = func(*args, **kwargs)
    
            stop = time.time()
            print('run time is %s' % (stop - start))
            return res
    
        return wrapper
    
    
    @timmer  # index=timmer(index)
    def index():
        time.sleep(3)
        print('welcome to index')
        return 123
    
    
    @timmer  # home=timmer(home)
    def home(name):
        time.sleep(2)
        print('welcome %s to home page' % name)
    
    
    # res=index() #res=wrapper()
    # print(res)
    
    res1 = home('egon')  # wrapper('egon')
    print(res1)
    装饰器返回值

    3、装饰器的使用

    import time
    def timmer(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
    
    @timmer
    def foo():
        time.sleep(3)
        print('from foo')
    foo()
    无参装饰器
    def auth(driver='file'):
        def auth2(func):
            def wrapper(*args,**kwargs):
                name=input("user: ")
                pwd=input("pwd: ")
    
                if driver == 'file':
                    if name == 'egon' and pwd == '123':
                        print('login successful')
                        res=func(*args,**kwargs)
                        return res
                elif driver == 'ldap':
                    print('ldap')
            return wrapper
        return auth2
    
    @auth(driver='file')
    def foo(name):
        print(name)
    
    foo('egon')
    有参装饰器

    4、装饰器语法

    被装饰函数的正上方,单独一行
            @deco1
            @deco2
            @deco3
            def foo():
                pass
    
            foo=deco1(deco2(deco3(foo)))
    

    5、加认证功能的装饰器

    current_user = {'user': None}
    
    
    def auth(func):
        def wrapper(*args, **kwargs):
            if current_user['user']:
                return func(*args, **kwargs)
    
            name = input('name: ').strip()
            password = input('password: ').strip()
    
            with open('db.txt', encoding='utf-8') as f:
                user_dic = eval(f.read())
            if name in user_dic and password == user_dic[name]:
                res = func(*args, **kwargs)
                current_user['user'] = name
                return res
            else:
                print('user or password error')
    
        return wrapper
    
    
    @auth  # index=auth(index) index=wrapper
    def index():
        print('from index')
    
    
    index()
    
    
    @auth
    def home(name):
        print('welcome %s' % name)
    
    
    index()  # wrapper()
    home('egon')
    无参版本
    current_user = {'user': None}
    
    
    def auth(auth_type='file'):
        def deco(func):
            def wrapper(*args, **kwargs):
                if auth_type == 'file':
                    if current_user['user']:
                        return func(*args, **kwargs)
                    name = input('name: ').strip()
                    password = input('password: ').strip()
    
                    with open('db.txt', encoding='utf-8') as f:
                        user_dic = eval(f.read())
                    if name in user_dic and password == user_dic[name]:
                        res = func(*args, **kwargs)
                        current_user['user'] = name
                        return res
                    else:
                        print('user or password error')
                elif auth_type == 'mysql':
                    print('mysql')
    
                elif auth_type == 'ldap':
                    print('ldap')
                else:
                    print('not valid auth_type')
    
            return wrapper
    
        return deco
    
    
    @auth(auth_type='mysql')  # @deco  #index=deco(index)
    def index():
        print('from index')
    
    
    @auth(auth_type='file')
    def home(name):
        print('welcome %s' % name)
    
    
    index()  # wrapper()
    home('egon')
    有参版本

    6、装饰器补充:wraps  

    from functools import wraps
    
    def deco(func):
        @wraps(func) #加在最内层函数正上方
        def wrapper(*args,**kwargs):
            return func(*args,**kwargs)
        return wrapper
    
    @deco
    def index():
        '''哈哈哈哈'''
        print('from index')
    
    print(index.__doc__)
    

    二、迭代器

    1、迭代的概念

    #迭代是一个重复的过程,每次重复即一次迭代,并且每次迭代的结果都是下一次迭代的初始值
    while True: #只是单纯地重复,因而不是迭代
        print('===>') 
        
    l=[1,2,3]
    count=0
    while count < len(l): #迭代
        print(l[count])
        count+=1
    

    2、为何要有迭代器?什么是可迭代对象?什么是迭代器对象?  

    #1、为何要有迭代器?
    对于序列类型:字符串、列表、元组,我们可以使用索引的方式迭代取出其包含的元素。但对于字典、集合、文件等类型是没有索引的,若还想取出其内部包含的元素,则必须找出一种不依赖于索引的迭代方式,这就是迭代器
    
    #2、什么是可迭代对象?
    可迭代对象指的是内置有__iter__方法的对象,即obj.__iter__,如下
    'hello'.__iter__
    (1,2,3).__iter__
    [1,2,3].__iter__
    {'a':1}.__iter__
    {'a','b'}.__iter__
    open('a.txt').__iter__
    
    #3、什么是迭代器对象?
    可迭代对象执行obj.__iter__()得到的结果就是迭代器对象
    而迭代器对象指的是即内置有__iter__又内置有__next__方法的对象
    
    文件类型是迭代器对象
    open('a.txt').__iter__()
    open('a.txt').__next__()
    
    
    #4、注意:
    迭代器对象一定是可迭代对象,而可迭代对象不一定是迭代器对象
    

    3、迭代器对象的使用  

    dic={'a':1,'b':2,'c':3}
    iter_dic=dic.__iter__() #得到迭代器对象,迭代器对象即有__iter__又有__next__,但是:迭代器.__iter__()得到的仍然是迭代器本身
    iter_dic.__iter__() is iter_dic #True
    
    print(iter_dic.__next__()) #等同于next(iter_dic)
    print(iter_dic.__next__()) #等同于next(iter_dic)
    print(iter_dic.__next__()) #等同于next(iter_dic)
    # print(iter_dic.__next__()) #抛出异常StopIteration,或者说结束标志
    
    #有了迭代器,我们就可以不依赖索引迭代取值了
    iter_dic=dic.__iter__()
    while 1:
        try:
            k=next(iter_dic)
            print(dic[k])
        except StopIteration:
            break
            
    #这么写太丑陋了,需要我们自己捕捉异常,控制next,python这么牛逼,能不能帮我解决呢?能,请看for循环
    

    4、for循环

    #基于for循环,我们可以完全不再依赖索引去取值了
    dic={'a':1,'b':2,'c':3}
    for k in dic:
        print(dic[k])
    
    #for循环的工作原理
    #1:执行in后对象的dic.__iter__()方法,得到一个迭代器对象iter_dic
    #2: 执行next(iter_dic),将得到的值赋值给k,然后执行循环体代码
    #3: 重复过程2,直到捕捉到异常StopIteration,结束循环
    

    5、迭代器的优缺点

    #优点:
      - 提供一种统一的、不依赖于索引的迭代方式
      - 惰性计算,节省内存
    #缺点:
      - 无法获取长度(只有在next完毕才知道到底有几个值)
      - 一次性的,只能往后走,不能往前退
    

    三、生成器  

    1、什么是生成器  

    #只要函数内部包含有yield关键字,那么函数名()的到的结果就是生成器,并且不会执行函数内部代码
    
    def func():
        print('====>first')
        yield 1
        print('====>second')
        yield 2
        print('====>third')
        yield 3
        print('====>end')
    
    g=func()
    print(g) #<generator object func at 0x0000000002184360>
    

    2、生成器就是迭代器

    g.__iter__
    g.__next__
    #2、所以生成器就是迭代器,因此可以这么取值
    res=next(g)
    print(res)
    

    3、练习

    1、自定义函数模拟range(1,7,2)

    2、模拟管道,实现功能:tail -f access.log | grep '404'

    #题目一:
    def my_range(start,stop,step=1):
        while start < stop:
            yield start
            start+=step
    
    #执行函数得到生成器,本质就是迭代器
    obj=my_range(1,7,2) #1  3  5
    print(next(obj))
    print(next(obj))
    print(next(obj))
    print(next(obj)) #StopIteration
    
    #应用于for循环
    for i in my_range(1,7,2):
        print(i)
    
    #题目二
    import time
    def tail(filepath):
        with open(filepath,'rb') as f:
            f.seek(0,2)
            while True:
                line=f.readline()
                if line:
                    yield line
                else:
                    time.sleep(0.2)
    
    def grep(pattern,lines):
        for line in lines:
            line=line.decode('utf-8')
            if pattern in line:
                yield line
    
    for line in grep('404',tail('access.log')):
        print(line,end='')
    
    #测试
    with open('access.log','a',encoding='utf-8') as f:
        f.write('出错啦404
    ')
    View Code

    3、tail.py -f access.log | grep 'error'

    import time
    
    
    def tail(filepath):
        with open(filepath, 'r') as f:
            f.seek(0, 2)
            while True:
                line = f.readline()
                if line:
                    yield line
                else:
                    time.sleep(0.2)
    
    
    def grep(pattern, lines):
        for line in lines:
            if pattern in line:
                print(line, end='')
    
    
    grep('error', tail('access.log'))
    View Code

    4、yield与return的比较?

    #相同:都有返回值的功能
    #不同:return只能返回一次值,而yield可以返回多次值  

    四、协程函数  

    #yield关键字的另外一种使用形式:表达式形式的yield
    def eater(name):
        print('%s 准备开始吃饭啦' %name)
        food_list=[]
        while True:
            food=yield food_list
            print('%s 吃了 %s' % (name,food))
            food_list.append(food)
    
    g=eater('egon')
    g.send(None) #对于表达式形式的yield,在使用时,第一次必须传None,g.send(None)等同于next(g)
    g.send('蒸羊羔')
    g.send('蒸鹿茸')
    g.send('蒸熊掌')
    g.send('烧素鸭')
    g.close()
    g.send('烧素鹅')
    g.send('烧鹿尾')
    View Code

    1、练习

    1、编写装饰器,实现初始化协程函数的功能

    2、实现功能:grep  -rl  'python'  /etc

    #题目一:
    def init(func):
        def wrapper(*args,**kwargs):
            g=func(*args,**kwargs)
            next(g)
            return g
        return wrapper
    @init
    def eater(name):
        print('%s 准备开始吃饭啦' %name)
        food_list=[]
        while True:
            food=yield food_list
            print('%s 吃了 %s' % (name,food))
            food_list.append(food)
    
    g=eater('egon')
    g.send('蒸羊羔')
    
    #题目二:
    #注意:target.send(...)在拿到target的返回值后才算执行结束
    import os
    def init(func):
        def wrapper(*args,**kwargs):
            g=func(*args,**kwargs)
            next(g)
            return g
        return wrapper
    
    @init
    def search(target):
        while True:
            filepath=yield
            g=os.walk(filepath)
            for dirname,_,files in g:
                for file in files:
                    abs_path=r'%s\%s' %(dirname,file)
                    target.send(abs_path)
    @init
    def opener(target):
        while True:
            abs_path=yield
            with open(abs_path,'rb') as f:
                target.send((f,abs_path))
    @init
    def cat(target):
        while True:
            f,abs_path=yield
            for line in f:
                res=target.send((line,abs_path))
                if res:
                    break
    @init
    def grep(pattern,target):
        tag=False
        while True:
            line,abs_path=yield tag
            tag=False
            if pattern.encode('utf-8') in line:
                target.send(abs_path)
                tag=True
    @init
    def printer():
        while True:
            abs_path=yield
            print(abs_path)
    
    
    g=search(opener(cat(grep('你好',printer()))))
    # g.send(r'E:CMSaaadb')
    g=search(opener(cat(grep('python',printer()))))
    g.send(r'E:CMSaaadb')
    View Code
  • 相关阅读:
    【DOM】如何给div的placeholder传参
    【nvm】使用nvm将node升级到指定版本
    【Worktile】升级业务组件库后,http的数据返回整个response而不是data问题及解决方案
    js获取上传文件内容
    【正则】正则表达式-零宽断言(?=,?<=,?!,?<!)及常见报错
    【Angular】动态组件
    【扩展】div获取焦点或可编辑
    【CSS】position新增属性sticky
    thinkphp写接口返回固定的形式方法
    thinkphp5计算文件大小
  • 原文地址:https://www.cnblogs.com/xiechao621/p/8007179.html
Copyright © 2011-2022 走看看