zoukankan      html  css  js  c++  java
  • 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 本文欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则视为侵权。

  • 相关阅读:
    leetcode 347. Top K Frequent Elements
    581. Shortest Unsorted Continuous Subarray
    leetcode 3. Longest Substring Without Repeating Characters
    leetcode 217. Contains Duplicate、219. Contains Duplicate II、220. Contains Duplicate、287. Find the Duplicate Number 、442. Find All Duplicates in an Array 、448. Find All Numbers Disappeared in an Array
    leetcode 461. Hamming Distance
    leetcode 19. Remove Nth Node From End of List
    leetcode 100. Same Tree、101. Symmetric Tree
    leetcode 171. Excel Sheet Column Number
    leetcode 242. Valid Anagram
    leetcode 326. Power of Three
  • 原文地址:https://www.cnblogs.com/RainBol/p/9825032.html
Copyright © 2011-2022 走看看