• python装饰器,迭代器,生成器,协程


    python装饰器[1]

      首先先明白以下两点

    #嵌套函数
    def out1():
        def inner1():
            print(1234)
        inner1()#当没有加入inner时out()不会打印输出1234,当前层级也就是作用域下必须调用函数才能引用
    out1()
    #函数作用域
    def out2():
        a = 'aaa'
        def inner2():
            a = 'bbb'
            print(a)
        inner2()
        print(a)
    out2()#当相同变量处于不同嵌套函数中,会根据作用函数由内而外查找

    装饰器:本质还是一个函数, 在不改变函数调用方式的情况下 对函数进行额外功能的封装,装饰一个函数 转给他一个其他的功能

    装饰器的目的:装饰器的原本是用来在项目上线之后,因为已经上线了,大批量改代码的话很麻烦,由此产生了装饰器

    1. 不能修改被装饰的函数的源代码
    2. 不能修改被装饰的函数的调用方式
    import time
    def demo():
        print("wo shi rainbol")
    def time1():
        start = time.time()
        demo()#给time1函数增加了一个demo的功能
        end  = time.time()
        print(end-start)
    time1()
    #这样方式很low,如果有一个添加n个函数添加此功能会很麻烦
    import time
    def demo():
        print("wo shi rainbol")
    def demo2():
        print("wo yeshi rainbol")
    def time1(fuc):
        start = time.time()
        fuc()#把之前的demo改成公用的fuc,函数即变量
        end = time.time()
        print(end-start)
    time1(demo)#通过调用time1方法,fuc赋值成了demo,再调用demo的方法
    time1(demo2)
    #time1(demo。。)
      以上完成了对任意函数改变调用方式进行了功能的封装,那如何用不改变调用方式的情况下对其进行功能的封装呢?
    import time
    def demo():
        print("wo shi rainbol")
    def time1(fuc):
        def inner():#根据之前学过的嵌套函数,增加一层inner方法,把值放入其中
            start = time.time()
            fuc()
            end = time.time()
            print(end-start)
        return inner#返回inner方法,但是没有运行
    demo = time1(demo)#time1包含了inner的功能/拿到inner的返回值并且赋值给res,装饰器的目的是不改变变量名所以这边仍然用demo变量赋值
    demo()#demo通过括号运行inner方法
    #下面通过真正的装饰器可以省去上面的步骤
    import time
    def time1(fuc):#2.time1(demo),这里的fuc相当于形参,其实就是demo
    def inner(): 
      start
    = time.time()
      fuc()
      end
    = time.time()
      
    print(end-start)
      
    return inner#3.返回inner函数,但没有执行哦
    @time1
    #1.python先会整体浏览一遍代码关键字的代码,找到了demo方法上头有装饰
        # 先调用装饰器,time1也就是demo = time1(demo),括号中的demo相当于实参
    def demo():
        print("wo shi rainbol")
    # demo = time1(demo)                <=====> @time1 去掉@time1在这家这段也是一样的
    demo()#4.现在才执行()执行函数
    #简单装饰器
    import time
    def simper(fuc):
        def inner(*args,**kwargs):
            start = time.time()
            fuc(*args,**kwargs)#增加的方法
            end = time.time()
            print(end - start)
        return inner
    @simper #demo = simper(demo)
    def demo(name):#定义一个方法
        print(name)#增加一个公用的功能点
    demo(1)
    #高级装饰器  当我们再原来装饰器的业务上再增加一个形参,来判断我们的业务是否符合指定的状态,这需要外面再套一层函数
    import time
    def harder(type):
        if type == 1:
            def out(fuc):
                def inner(*args,**kwargs):
                    start = time.time()
                    fuc(*args,**kwargs)
                    end = time.time()
                    print(end - start)
                return inner
            return out
        elif type == 2:
            pass
    @harder(1)#返回out函数
    def demo(name):
        print(name)
    demo(1)

      其他可以参考https://blog.csdn.net/u013471155/article/details/68960244  这个写得很详细

    python装饰器[2]

    装饰器与之间的迭代

      下面是产品四次提出需求后再不修改调用参数使用装饰器在修改lose函数来完成我们业务上的需求,原因是上线项目许多接口都调用我们这个类下的参数,再不破坏接口本身情况下使用装饰器迭代是最佳选择

    import time
    
    
    # 现在有一个需求1.0:在整个功能的基础上再添加一个减去4.5的操作使得最后结果为0,前提条件是不修改调用参数
    def outer(fuc):
        def inner(*args, **kwargs):
            a = fuc(*args, **kwargs) - 4.5
            return a
    
        return inner
    
    
    # 迭代需求1.1:在整个功能的基础上再添加一个增加10的操作使得最后结果为10,提前条件是不修改调用参数
    def outer2(fuc2):
        def inner2(*args, **kwargs):
            b = fuc2(*args, **kwargs) + 10
            return int(b)
    
        return inner2
    
    
    # 迭代需求1.2:在整个功能的基础上再添加一个时间参数判断lose函数的时间,目前为了模拟添加2秒延迟时间,提前条件是不修改调用参数
    def showtime(fuc):
        def inner3(*args, **kwargs):
            starttime = time.time()
            a = fuc(*args, **kwargs)
            time.sleep(2)
            endtime = time.time()
            b = endtime - starttime
            return a, b
    
        return inner3
    
    
    # 迭代需求2.0:目前项目的lose的方法在业务繁忙时会异常中断,为此接口添加异常处理,提前条件是不修改调用参数
    def tryexception(fuc):
        def tryer(self, *args, **kwargs):
            try:
                res = fuc(self, *args, **kwargs)
            except Exception as e:
                self.lose()
                return 'ERROR'
            return res
    
        return tryer
    
    '''主程序'''
    class MyDecorato(object):
        def __init__(self):
            pass
    
        def chengxu(self, a, b):
            c = a + b
            return c
    
        @tryexception #4.最后调用tryexception装饰器,装饰器之间调用是从下到上来依次调用
        @showtime  # 3.调用showtime装饰器
        @outer2  # 2.调用outer2装饰器
        @outer  # 1.先调用outer装饰器
        def lose(self, c):#频繁调用的函数lose
            pingjun = c / 2
            return pingjun
    
    
    d = MyDecorato()
    res1 = d.chengxu(6, 3)
    res2, time = d.lose(res1)
    print('最后的值:', res2, '时间:', time)

     python装饰器[3]

    #wrap函数为functools标准库中模块
    def test():
        '''i am test'''
        print('一个简单的实验')
    
    test()
    print(test.__doc__)
    print(test.__name__)
    #
    #>> 一个简单的实验
    #>> i am test
    #>> test
    print('--------------------------------')
    def outer(fuc):
        '''outer is me'''
        print('this is outer')
        def inner(*args,**kwargs):
            '''inner is me'''
            print('this is inner1')
            fuc(*args,**kwargs)
            print('this is inner2')
        return inner
    
    
    @outer
    def test():
        '''i am test'''
        print('一个简单的实验')
    
    test()
    print(test.__doc__)
    print(test.__name__)
    
    #>> this is outer
    #>> this is inner1
    #>> 一个简单的实验
    #>> this is inner2
    #>> inner is me
    #>> inner
    
    print('-----------------------')
    #如果我们想要得到test里面的数据就要调用一个特定装饰器来帮我们实现
    
    import functools
    def outer(fuc):
        '''outer is me'''
        print('this is outer')
       # @functools.wraps(fuc)
        def inner(*args,**kwargs):
            '''inner is me'''
            print('this is inner1')
            fuc(*args,**kwargs)
            print('this is inner2')
        #return inner
        return functools.update_wrapper(inner,fuc)#@functools.wraps(fuc)也可以,update_wrapper是调用其内部wrapper
    @outer
    def test():
        '''i am test'''
        print('一个简单的实验')
    test()
    print(test.__doc__)
    print(test.__name__)
    #>> this is outer
    #>> this is inner1
    #>> 一个简单的实验
    #>> this is inner2
    #>>> i am test
    #>> test
    
    
    print('------------------')
    #保持wrapper和test的属性值一样,这样也可以实现同样的效果
    import functools
    def outer(fuc):
        '''outer is me'''
        print('this is outer')
        def inner(*args,**kwargs):
            '''inner is me'''
            print('this is inner1')
            fuc(*args,**kwargs)
            print('this is inner2')
        inner.__doc__ = fuc.__doc__
        inner.__name__ = fuc.__name__
        return inner
    @outer
    def test():
        '''i am test'''
        print('一个简单的实验')
    
    test()
    print(test.__doc__)
    print(test.__name__)

     python装饰器[4]

    #通过类中的装饰器实现,普通方式
    
    class Foo(object):
        def __init__(self):
            pass
    
        def decorator(foo):
            def inner(self):
                print('before')
                foo(self)
                print('after')
    
            return inner
    
        @decorator
        def test(self):
            print('testing')
    
    
    foo = Foo()
    foo.test()
    #通过类中的装饰器实现,继承方式
    class Foo(object):
        def __init__(self):
            pass
    
        def decorator(self):
            def inner(*args, **kwargs):
                print('before')
                self(*args, **kwargs)
                print('after')
    
            return inner
    
        @decorator
        def test1(self):
            print('我被执行了')
    
    
    class Foo2(Foo):
        @Foo.decorator  # 执行被继承的方法
        def decorator(self):
            print('执行被继承的方法开始')
            super(Foo2, self).test1()  # 运行Foo2父类Foo的test1方法
            print('执行被继承的方法结束')
    
    
    foo = Foo()
    foo.test1()
    print('-----')
    foo2 = Foo2()
    foo2.decorator()
    #实例
    class Test1(object):
        def decorator1(self):
            def inner(*args, **kwargs):
                self(*args, **kwargs)
                print('n年前添加的附加功能')
    
            return inner
    
        @decorator1
        def test1(self):
            print('n年前实现的某个功能')
    
    
    class Test2(Test1):
        def decorator2(self):
            def inner(*args, **kwargs):
                self(*args, **kwargs)
                print('今天添加的附加功能')
    
            return inner
    
        @decorator2
        def test2(self):
            super(Test2, self).test1()
            print('昨天自己实现的功能')
    
    
    foo = Test2()
    foo.test2()
    View Code
    #通过类中的装饰器实现,获取对象方法的实例属性
    def mod_test(cls):
        # 返回修改的类
    
        def decorator(fun):
            # 返回装饰函数
    
            def new_fun(self):
                print(self.before)
                print(fun(self))
                print(self.after)
    
            return new_fun
    
        cls.test = decorator(cls.test)
        return cls
    
    
    @mod_test
    class Foo(object):
        def __init__(self):
            self.before = "before"
            self.after = "after"
    
        def test(self):
            return "testing"
    
    
    foo = Foo()
    foo.test()

     python迭代器

    l = [1,2,3,4,5,6]
    print(l.__iter__())  #iter(l)  这两者是一样的,都返回了一样迭代器对象 <list_iterator object at 0x00000000023B7080>
    d = (iter(l))
    print((next(d)))#返回 1
    print((next(d)))#返回 2
    #所以生成器本身就是迭代器
    
    #for循环本身主要做的三件事:
    
    for i in [1,2,34,5,5]:
    # 1.
       iter([1,2,34,5,5])#调用可迭代对象的iter方法返回一个迭代器对象
    # 2.调用迭代器对象的next方法
    # 3.处理Stoplteration
    
    #校验
    from collections import Iterator,Iterable
    # Iterable  迭代器
    # Iterator 迭代对象
    print(isinstance([1334],list))#判断给对象是否为一个list,返回布尔值
    print(isinstance(l,Iterable))#判断是否是迭代对象,返回布尔值

      自定义迭代器

    class Mytest:
        def __init__(self, len):
            self.index = 0
            self.len = len
    
        def __iter__(self):
            return self
    
        def __next__(self):
            if self.index < self.len:
                self.index += 1
                return self.index
            raise StopIteration
    
    
    for i in Mytest(20):
        print(i)
    #打印1-20,迭代器底层调用,结构复杂

     python生成器

      用法1:

    f = (x for x in range(1000))#使用列表生成式外面套了一层中括号并赋值给f对象
    print(f)#此时f打印的就是一个生成器对象  <generator object <genexpr> at 0x0000000001DD79E8>
    #此时需要打印x必须如下方式,生成器就像一位厨师,做出x就是一盘盘菜,每一盘菜必须吃完再吃第二盘,而且不能跳着吃,倒着吃
    print(next(f))#调用使用next()比较常见
    print(next(f))
    print(next(f))
    print(f.__next__())#f.__next__()也是可以的        py2的调用方式是f.next直接调用
    print(f.__next__())
    print(f.__next__())

      用法2:

    #yield也是生成器中的例子,如果在没有使用next(),函数根本不会被执行,调用每一次程序会检测yield如果有,yield包括后面的代码不会执行,直到下次调用才执行下次的,所以函数中只要有yield就是生成器
    #yield可以理解成return
    def test(len):
        print(len,'11')
        yield 1
        print(len,'222')
        yield 2
        print(len,'333')
    test('1')#此函数不会被调用
    for i in test('1'):#for内置有生成器next,可以对生成器对象一直使用next(n)
        print(i,'调用')
    #打印
    # 1 11
    # 1 调用
    # 1 222
    # 2 调用
    # 1 333
    #这个就是异步io的原理了,python里面的协程基于yield实现
    #生成器的好处:
    #如果我们写一个    danger = [x for x in range(9999999999999999999)]
    # 当我们打印danger时我们的电脑会在内存中放置0-n的数据,造成内存不足,死机的情况,生成器的出现会把旧变量替换成新变量,从而不会造成大数据所产成内存泄露的问题
    nodanger = (x for x in range(999999999999999999999999))
    print(next(nodanger))

    协程

      简单的说只要能够完成多任务切换的都是协程,规避io操作是协程体现出的效果

      yield是协程最底层的使用方法

    #yield的使用
    def f():
        print('jjjj')
        yield 1
        print('gggg')
        yield
    print(f())#创建一个生成器对象,但是函数不会执行
    
    
    
    gen = f()
    #next(gen)#执行生成器对象
    gen.send(None)
    x = gen.send(10)#next(gen)这两者是一样的
    print(x)

      gevent模块

    #gevent模块 在gevent中主要模式就是greenlet,它是c扩展的轻量级协程
    from greenlet import greenlet
    def test1():
        print('111')
        b.switch()
        print('333')
        b.switch()
    def test2():
        print('222')
        a.switch()
        print('444')
    a = greenlet(test1)#创建一个生成器对象
    b = greenlet(test2)
    a.switch()
    # from gevent import monkey
    # monkey.patch_all()#实时监听io堵塞,效果显著,要注意的是这两句话要放到最上面不然就会报错,我也不知道为什么
    import gevent
    def test3():
        print('模拟io堵塞1')
        gevent.sleep(1)#模拟堵塞时间
        print('堵塞消除1')
    def test4():
        print('模拟io堵塞2')
        gevent.sleep(2)
        print( '堵塞消除2')
    
    gevent.joinall([gevent.spawn(test3),gevent.spawn(test4)])
    #joinall效果是如果两个方法中其中一个出现io堵塞,会跳到另外一个方法,如果都堵塞都会等着,直到io堵塞消除
    #优势:io堵塞的时间取决于io堵塞最长的时间,提升效率

     协程实例:

    
    
    from gevent import monkey
    monkey.patch_all()
    #gevent模块  #基于greenlet封装,避免多线程切换导致io执行效率降低
    import gevent
    import requests
    
    def run(name, url):
        r = requests.get(url)
        open(name + '.html', 'wb').write(r.content)
    url = {'rainbol01': 'https://www.cnblogs.com/RainBol/',
           'rainbol02': 'https://www.cnblogs.com/RainBol/p/9505438.html',
           'rainbol03': 'https://www.cnblogs.com/RainBol/p/10077388.html'
           }
    for name, url in url.items():
        g = gevent.spawn(run, name, url)  # 启动
        g.join()  # 等待并切换
    
    #阻塞等待分配任务完成后结束
    # l = []
    # for i in range(10):
    #     g = gevent.spawn(run,name,url)
    #     l = g.append(g)
    # g.joinall(l)

     https://www.cnblogs.com/RainBol/p/13612932.html  更多协程

    版权声明:本文原创发表于 博客园,作者为 RainBol 本文欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则视为侵权。

  • 相关阅读:
    [django]media_url
    django部署到apache出现DLL load failed

    Django model relationship field
    python下划线变量的含义
    JavaScript 对象属性作实参以及实参对象的callee属性
    Javascript变长参数和默认参数
    JavaScript 数组
    JavaScript 操作对象属性(设置属性, setter/getter, 序列化)
    JavaScript 对象笔记
  • 原文地址:https://www.cnblogs.com/RainBol/p/9825032.html
Copyright © 2020-2023  润新知