zoukankan      html  css  js  c++  java
  • python装饰器,迭代器,生成器

    • 什么是装饰器?

    装饰器是装饰其它函数,为其它函数增加特定功能。在原来的函数上,增加一些限制或制约的条件,称为装饰器。

    使用装饰器不会修改原函数的源码,也不会修改原函数的调用方式。

    装饰器的基础知识有,函数也是变量,高阶函数,嵌套函数。

    函数名和变量名一样只是一个变量的标识符,指向函数定义的内存地址。在函数定义中取调用其它函数时,不会立即调用调用该函数。

    高阶函数的两个要求为,在函数形参中可以传递函数,函数的返回值包含函数名。

     1 import time
     2 def timer(func):      #定义装饰器函数
     3     def gcf():           #定义一个嵌套函数
     4         start_time=time.time()
     5         func()            #调用作为参数传入的函数名 
     6         end_time=time.time()
     7         print('程序运行时间',end_time-start_time)
     8     return gcf          #返回嵌套函数的函数名
     9 @timer
    10 def foo():              #定义被装饰函数
    11     time.sleep(1)
    12     print('in foo')
    13 foo()
    14 #执行过程
    15 #到达第二行,装饰器函数的定义,把装饰器函数整体加载到CPU
    16 #到达第九行,语句的执行过程实际是foo=timer(foo),所以执行timer函数
    17 #回到第三行,把嵌套函数gcf整体加载到CPU
    18 #执行到第八行,返回一个嵌套函数名给装饰器函数timer,也即返回函数名给foo
    19 #到达第十四行,执行返回的foo函数,又回到第三行,执行foo函数体
    20 #到达第五行,执行func函数,转到第十行
    21 #执行了func函数后,依次执行程序,直到结束程序

    当被装饰函数中有参数时,参数传递过程遵循一定的规则。被装饰函数中有一个参数,使用以下方式。

    import time
    def timer(func):      #定义高阶函数,参数传递foo,装饰foo
        def gf(name):     #定义嵌套函数,装饰foo
            start_time=time.time()
            func(name)     #执行被装饰函数
            end_time=time.time()
            print('程序运行时间',end_time-start_time)
        return gf             #在高阶函数中返回嵌套函数
    @timer
    def foo(name):       #被装饰函数中有参数
        time.sleep(1)
        print('in foo',name)
    foo('woniu')

    被装饰函数有多个参数时,需要使用不定义参数传参

    import time
    def timer(func):
        def gf(*args,**kwargs):
            start_time = time.time()
            func(*args,**kwargs)
            end_time = time.time()
            print('程序运行时间为',end_time-start_time)
        return gf
    @timer
    def foo(name,age):
        time.sleep(1)
        print('in foo',name,age)
    foo('woniu',24)

    在装饰函数中传递参数,需要使用以下的规则

    import time
    def timer(timer_type):     #定义高阶函数作为装饰器,带有参数
        def outter(func):          #定义嵌套函数,参数为被装饰函数
           def inner(*args,**kwargs):      #定义嵌套函数,参数为被装饰函数的参数
              start_time=time.time()
              func(*args,**kwargs)         #调用被装饰函数
              end_time=time.time()
            return inner            #返回内层嵌套函数
        return outter               #返回外层嵌套函数
    @timer(timer_type='min')
    def foo(name,args):         #定义被装饰函数
        time.sleep(1)
        print('in foo',name,age)
    foo('woniu',24)

    被装饰函数有返回值,遵循如下规则

    import timer
    def timer(timer_type):    #定义高阶函数为装饰器函数,带有参数
        def outter(func):         #定义嵌套函数,参数为被装饰函数
            def inner(*args,**kwargs)     #定义嵌套函数,被装饰函数有参数
                start_time = time.time()
            res = func(*args,**kwargs)
            end_time = time.time()
            print('程序运行时间为',end_time-start_time)
                return res          #返回被装饰函数的返回值
            return inner           #返回内层嵌套函数
        return outter              #返回外层嵌套函数
    @timer(timer_type='min')
    def foo(name,age):        #定义被装饰函数,有返回值,有多个参数
        time.sleep(1)
        print('in foo',name,age)
        return name
    print(foo('woniu',24))      #输出被装饰函数的返回值
    •  迭代器

    在Python的任意对象中,定义了返回一个迭代器的__iter__方法,或定义了支持下表索引的__getitem__方法,就称为可迭代对象。

    #判断可迭代对象的两种方式
    form collections import Iterable
    print(isinstance([],Iterable))      #使用isinstance方法判断
    print(hasattr([],'__getitem__'))  #使用是否具有方法__getitem__判断
    class emp():                      #定义对象
        def __init__(self,employee):
            self.employee=employee
        def __getitem__(self,item):      #定义方法,表示是一个可迭代对象
            return self.employee[item]   #返回一个类中的属性
    emp=emp(['张三','李四','王五'])
    for i in emp:                #emp对象增加了__getitem__对象后,变成了可迭代对象
        print(i)

    迭代器就是包括一个__iter__方法来返回迭代器本身,__next__方法返回迭代器的下一个值。

    有了可迭代对象,为什么还需要迭代器?这是因为迭代器是一个工厂模式,是懒加载。预先不需要指定迭代器的大小,是根据需要动态的加载空间。所以也就没有长度属性。

    from itertools import count
    from collections import iterator
    counter=count(start=10)      #定义了一个迭代器对象
    for i in range(10):     #只需要指定循环次数,就可以随机生成迭代器
        print(next(counter))       #每次循环都输出下一个迭代器值
    print(isinstance(counter,iterator))     #判断是否迭代器
    a=[1,2,3,4,5,6]      #列表为可迭代对象
    a_iter=iter(a)         #列表强制转为迭代器
    for item in a_iter:   #对迭代器进行迭代
        print(item)
    #迭代器对象进行迭代后,不能再次迭代。可迭代对象迭代后,依然可以迭代。
    • 生成器

    生成器是一个特殊的迭代器,不需要写__next__方法,__iter__方法,只需要在函数内部写一个yield关键字即可。

    使用yield关键字,可以返回一个值。也可以保留函数的运行状态,等待下次函数的执行,函数下次执行是从yield语句后开始执行。

    def demo():        #定义生成器
        print('hello')
        yield 5
        print('world')
    c=demo()            #只是生成生成器对象,不运行
    print(next(c))       #调用生成器,输出hello,由于yield返回5,再输出5
    next(c)                #在此输出world,程序从上次yield语句后开始执行

    生成器的两种调用方法。next方法,send方法。

    send方法也能够调用生成器,同时还会传递一个数据到生成器内部。

    生成器的两种预激活机制。使用next方法,使用c.send(None)方法传递一个空值到生成器内部。

    • 协程

    协程是一种微线程,是一种用户级的轻量级线程。在同一个线程中,不同子程序可以中断转去执行其它程序,在执行结束后,又回来继续执行中断前的程序。这种任务调度的模式称为协程。协程拥有自己的上下文,寄存器和栈。

    def consume():          #定义消费者
        r=''
        while True:
            n=yield r           #出现yield关键字,表示是一个生成器
            print('[consumer] consuming %s' %n)
            r='200 OK'
    def produce(c):          #定义生产者
         c.send(None)        #启动消费者
         n=0
         while n<5:
            n=n+1
            print('[producer] produceing %s' %n)
            r=c.send(n) 
            print('[producer] consumer return %s' %n)
    c=consume()
    produce(c)

    执行过程

    使用协程可以降低系统的开销,不想创建线程那样创建协程。也不必使用锁的机制来控制不同线程之间的运行。因为协程本来就是在一个线程之中运行。  

    import asyncio
    from collections.abc import Generator,Coroutine
    @asyncio.coroutine     #使用装饰器来定义协程
    def hello():                 #定义测试函数
        pass
    async def hello():        #使用async关键字来定义协程
        pass
    h=hello()
    print(isinstance(h,Generator))      #测试是否生成器
    print(isinstance(h,Coroutine))      #测试是否协程
    #使用装饰器方法定义协程属于一个生成器,
    #使用原生协程定义方法定义协程就属于一个协程

    使用asyncio框架来执行协程

    import asyncio
    async def hello(name):              #定义协程函数
        print('hello',name)
    h=hello('woniu')                        #定义协程对象
    loop=asyncio.get_event_loop()           #定义事件循环对象容器
    task=loop.create_task(h)                    #将协程对象转为task
    task=asyncio.ensure_future(h)   #将协程对象转为task的另一种方法
    loop.run_until_complete(task)     #将task放到事件循环对象容器中运行

    由于协程使用在异步I/O中,在协程中需要回调函数,来返回某个协程被中断后执行操作的结果。

    import asyncio
    async def hello(x):                 #定义协程函数
        await asyncio.sleep(x)          #异步操作,休眠当前协程
        return x             #在协程休眠后,执行操作,返回操作的结果
    h=hello(2)                   #定义协程对象
    loop=asyncio.get_event_loop()      #定义事件循环对象容器
    task=asyncio.ensure_future(h)       #将协程对象转为task
    loop.run_until_complete(task)        #事件循环对象执行task
    print('返回结果:{}'.format(task.result()))     #协程休眠后,执行的操作结果保存在task.result()方法中
    #上述方法仅适用在返回操作结果。如果要对返回结果进行操作,再返回就需要使用函数
    async def hello(x):                  #定义协程函数
        await asyncio.sleep(x)    #异步操作,休眠当前协程
        return x           #协程休眠结束,返回中断操作执行的结果
    def callback(future):        #定义回调函数
        sum=10+future.result()        #不经过任何操作的返回结果存放在future.result()方法中
        print('返回结果:',sum)
    h=hello(2)
    loop=asyncio.get_event_loop()     #创建事件循环对象容器
    task=asyncio.ensure_future(h)      #将协程对象转为task
    task.add_done_callback(callback)     #将回调函数添加到task中
    loop.run_until_complete(task)       #事件循环对象容器中执行task

    使用协程并发操作,使用更少的资源完成大的运行任务。

    import asyncio
    import time
    def hello(x):     #定义协程函数
        print('等待:',x)
        await asyncio.sleep(x)     #协程休眠
        return '等待了{}'.format(x)
    if __name__=='__main__':
        start=time.time()
        h1=hello(1)      #定义多个协程对象
        h2=hello(2)
        h3=hello(3)
        tasks=[        #将协程对象转task放到列表中
            asyncio.ensure_future(h1),   
            asyncio.ensure_future(h2),
            asyncio.ensure_future(h3)               
        ]
        loop=asyncio.get_event_loop()
        loop.run_until_complete(asyncio.wait(tasks))     #使用    asyncio.wait()方法运行多个task
        for task in tasks:
        print('任务返回结果:',task.result())
        print('程序运行时间是',time.time()-start)

    使用协程和多线程生成多数文件比较两者之间的性能

    import asyncio
    import time
    async def write(path,x):         #定义协程执行体,生成文件
        with open(path,'w') as f:
            f.write('this is file %s' %x)
    if __name__=='__main__':
        start=time.time()      #设置标记开始时间
        loop=asyncio.get_event_loop()      #创建事件循环对象容器
        tasks=[]
        for i in range(10000):       #创建一万个文件
            tasks.append(write('/Users/tone/Desktop/h/'+str(i)+'.txt',i))
        loop.run_until_complete(asyncio.wait(tasks))  #运行多个协程
        print('程序的执行时间:',time.time()-start)
    #上述方法使用协程创建一万个文件
    #以下方法使用多线程创建一万个文件
    import threading
    import time
    def write(path,x):      #定义线程函数
        with open(path,'w') s f:
            f.write('this is fiile %s' %x)
    if __name__=='__main__':
        start=time.time()
        therads=[]
        for i in range(10000):       #创建一万个文件
            t=threading.Thread(target=write,args=('/Users/tone/Desktop/h/'+str(i)+'.txt'',i))
            threads.append(t)
            t.start()
        [t.join() for t in threads]
        print('程序的执行时间:',time.time()-start)
  • 相关阅读:
    xml读写
    scrollWidth,clientWidth与offsetWidth的区别
    DIV+CSS设计时浏览器兼容性
    访问IIS客户端出现server application error解决方案
    网站局域网内不能访问解决方法之一
    xml学习笔记(一)
    文本编辑器FCKeditor
    业务部门需要IT人员为其提供什么
    程序员与VBA之怪现状
    你的代码完成了吗?(之一)——可用性和易用性
  • 原文地址:https://www.cnblogs.com/feng1014/p/12635121.html
Copyright © 2011-2022 走看看