zoukankan      html  css  js  c++  java
  • day6-基础 装饰器,生成器,迭代器


    1.装饰器

    定义:给其他函数装饰(添加附加功能)的函数

    原则:1.不能修改被装饰的函数的源代码。

          2.不能修改北庄施的函数的调用方式

    实现所需要求:1.函数即便量

              2.高阶函数

            3.嵌套函数

        高阶函数+嵌套函数=> 装饰器

    匿名函数:

    1 f = lambda x:x+1
    2 print(f(1))
    3 >>>2
    4 #匿名函数比起正常函数,不需要指定函数名
    View Code

     嵌套函数:

     1 x = 1
     2 def a():
     3     x = 2
     4     print(x)
     5     def b():
     6         x = 3
     7         print(x)
     8         def c():
     9             x = 4
    10             print(x)
    11         c()
    12     b()
    13 a()
    14 >>>2
    15        3
    16        4
    17 #嵌套函数调用要一层一层的调用,如果b没有调用那么只会打印"2"
    View Code

    举一个简单的装饰器例子:

    学渣版:

     1 def timer(func):
     2     def deco(*args,**kwargs):      #非固定参数传入
     3         start_time = time.time()  #计算开始时间
     4         func(*args,**kwargs)            #运行test1
     5         stop_time = time.time()   #计算结束时间
     6         print("运行时间为%s" % (start_time-stop_time)) #"deco"装饰器的作用-计算test1的运行时间
     7     return deco
     8 @timer   #还有一种调用方式,test1=timer(test1),但是这种比较麻烦还是推荐这种,你要装饰哪一个函数就在哪一个函数头部引用
     9 def test1(a,b):  
    10     time.sleep(3)  #三秒后运行
    11     print("in the test1:%s %s" % (a,b))  
    12 test1("123","234")  #并没有改变函数的调用方式和源代码 
    13 >>>in the test1:123 234
    14     运行时间为-3.0027999877929688
    15 这样应该就明白装饰器的作用了
    View Code

     学霸版:

     1 user,passwd = 'zhaoyue','woaini'
     2 def auth(func):             #这里假装我们有两个页面需要验证,这个函数用来验证
     3     def wrapper(*args,**kwargs):        
     4         username = input("Please your username:")
     5         password = input("Please your password")
     6         if user == username and passwd == password:
     7             print("Hello world!")
     8             func(*args,**kwargs)   #开始运行传入的函数
     9         else:
    10             exit("gun")
    11     return wrapper                      #返回结果
    12 
    13 def LOL():
    14     print("in the LOL")
    15 @auth
    16 def LPL():
    17     print("in the LPL")
    18 @auth
    19 def LCK():
    20     print("in the LCK")  
    21 LOL()
    22 LPL()
    23 LCK()  #后面则是"LPL",“LCK”需要验证。                     
    View Code

    学霸进阶版(这就是学渣和学霸的区别,一道题学渣考虑的是能不能做出来,而学霸考虑的是用几种方法做出来!!!)

     1 user,passwd = 'zhaoyue','woaini'
     2 def auth(auth_type):
     3     print("33[32;1m%s33[0m"% auth_type)
     4     def outer(func):
     5         def wrapper(*args,**kwargs):
     6             print("wrapper func args",*args,**kwargs)
     7             username = input("Please your username:")
     8             password = input("Please your password:")
     9             if user == username and passwd == password:
    10                 print("Hello world!")
    11                 res = func(*args,**kwargs)
    12                 return res
    13             else:
    14                 exit("gun")
    15         return wrapper
    16     return outer
    17 
    18 def LOL():
    19     print("in the LOL")
    20 @auth(auth_type="local")
    21 def LPL():
    22     print("in the LPL")
    23 @auth(auth_type="ldap")
    24 def LCK():
    25     print("in the LCK")
    26 LOL()
    27 LPL()
    28 LCK()
    29 >>>local
    30 ldap
    31 in the LOL
    32 wrapper func args
    33 Please your username:zhaoyue
    34 Please your password:woaini
    35 Hello world!
    36 in the LPL
    37 wrapper func args
    38 Please your username:zhaoyue
    39 Please your password:woaini
    40 Hello world!
    41 in the LCK
    View Code

     2.生成器

    现在有个需求:有列表[0, 1, 2, 3, 4, 5, 6, 7, 8, 9],要求把每个值加一并打印

    你可能有两种方式:

    a = [0,1,2,3,4,5,6,7,8,9]
    b = []
    for i in a:
        b.append(i+1)
    print(b)
    [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
    还有就是原值修改。。太low这里就不写了

    那么我们用生成器怎么写呢?

    a = [i+1 for i in range(10)]
    print(a)
    >>>[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

    其实真正的生成器应该去掉[]改成(),这样它就会在你调用的时候才会出现值。举个栗子:

    b = (i*3 for i in range(1000000))
    print(b)
    print(b.__next__())               #生成器的调用方式只有这一种b.__next__(),而且只能有一个一个的调用
    print(b.__next__())
    
    >>><generator object <genexpr> at 0x00000000023AA5C8>#这里出现个"gencerator",就是生成器的意思
       0
       3
    #这样一个一个调用显得麻烦,所以:
    b = (i*3 for i in range(1000000))
    for i in b:
        if i == 3000:  #取值3000次
            print(i)
    print(i)              #最后i的值
    3000
    2999997

    在数学上有一个斐波那契数列,除了前面两个数,任意一个数都是整数前面两个数的相加

     1,1,2,3,5,8,13,21,34,55..... 

    这里其实我们可以用生成器的方式去显示:

     1 def fib(max):
     2     n,a,b = 0,0,1
     3     while n <max:
     4         a,b = b,a+b
     5         print(a,b)
     6         n += 1
     7     return "done"
     8 fib(15)
     9 >>>1 1
    10 1 2
    11 2 3
    12 3 5
    13 5 8
    14 8 13
    15 13 21
    16 21 34
    17 34 55
    18 55 89
    19 89 144
    20 144 233
    21 233 377
    22 377 610
    23 610 987
    View Code

     诶。。。其实这里我们还离真正真正的生成器就差一步

     1 def fib(max):
     2     n,a,b = 0,0,1
     3     while n <max:
     4         a,b = b,a+b
     5         # print(a,b)
     6         yield a,b                         #将print改成yield
     7         n += 1
     8     return "done"
     9 f_gen = fib(15)
    10 print(f_gen.__next__())
    11 print("Hello world")
    12 print(f_gen.__next__())
    13 print(f_gen.__next__())
    14 print("Bye world")
    15 for i in f_gen:
    16     print(i)
    17 >>>(1, 1)
    18 Hello world
    19 (1, 2)
    20 (2, 3)
    21 Bye world
    22 (3, 5)
    23 (5, 8)
    24 (8, 13)
    25 (13, 21)
    26 (21, 34)
    27 (34, 55)
    28 (55, 89)
    29 (89, 144)
    30 (144, 233)
    31 (233, 377)
    32 (377, 610)
    33 (610, 987)
    34 #这样生成器就算完成了,取值的时候可以从生成器中出来干别的,也可以随时进去,这样不会从头开始,取值取到哪里就卡在哪里
    View Code

    但是用for循环调用generator时,发现拿不到generator的return语句的返回值。如果想要拿到返回值,必须捕获StopIteration错误,返回值包含在StopIterationvalue中:

    def fib(max):
        n,a,b = 0,0,1
        while n <max:
            a,b = b,a+b
            # print(a,b)
            yield a,b                         
            n += 1
        return "done"
    f_gen = fib(5)
    
    while True:
        for i in next(f_gen):
            print(i)                 #这样肯定会报"StopIteration",所以我们用try来捕获这个错误
    while True:
        try:
            x = next(f_gen)
            print('f_gen:',x)
        except StopIteration as e:     #捕获错误
            print("Gen return value:",e.value)  #打印错误的返回值
            break          

    还可以使用yield实现在单线程的情况下并发运算

     1 import time
     2 def xiaofeizhe(name):             #不要在意这里的英文"消费者"
     3     print('%s准备吃包子了'%name)
     4     while True:
     5         baozi = yield                              #yield就是你要把什么传到外面就写什么
     6         print("包子[%s]被[%s]吃了"%(baozi,name ))
     7 
     8 def shangjia():                      #还有这里的"商家"英文也不要在意
     9     x1 = xiaofeizhe('A')           #给"xiofeizhe(name)"传值
    10     x2 =  xiaofeizhe('B')          #给"xiofeizhe(name)"传值
    11     x1.__next__()
    12     x2.__next__()
    13     print("做包子ING")
    14     for i in range(10):           #循环10次把每次循环的数传给"baozi"(言外之意就是"send"可以给"yield"传值)
    15         time.sleep(1)
    16         x1.send(i)
    17         x2.send(i)        
    18 shangjia()                
    View Code

     3.迭代器

    到现在,可以直接for循环的数据类型有:

    list,dict,set,str还有刚学的生成器"generatior"

    这些可以直接for循环的对象被称为迭代器:Iterable

    可以使用"isinstance()"判断一个对象是否是Iterable对象:

     1 from collections import Iterable
     2 print(isinstance([],Iterable))
     3 >>>True
     4 print(isinstance('str',Iterable))
     5 >>>True
     6 print(isinstance({},Iterable))
     7 >>>True
     8 print(isinstance(1,Iterable))
     9 >>>Flase
    10 a=(i*2 for i in range(10))
    11 print(isinstance(a,Iterable))
    12 >>>True
    View Code

    而生成器不但可以作用于for循环,还可以被next()函数不断调用并返回下一个值,直到最后抛出StopIteration错误表示无法继续返回下一个值了

    可以被next()函数调用并不断返回下一个值的对象称为迭代器:Iterator

    可以使用isinstance()判断一个对象是否是Iterator对象:

    from collections import Iterator
    print(isinstance([],Iterator))
    >>>False
    print(isinstance('str',Iterator))
    >>>False
    print(isinstance({},Iterator))
    >>>False
    print(isinstance(1,Iterator))
    >>>False
    a=(i*2 for i in range(10))
    print(isinstance(a,Iterator))
    >>>True
    View Code

    也就是说,list,dict,set,str这种数据类型是Iterable,Iterator对象可以被next()函数调用并不断返回下一个数据


  • 相关阅读:
    Load Balancing 折半枚举大法好啊
    Big String 块状数组(或者说平方分割)
    K-th Number 线段树(归并树)+二分查找
    D. Powerful array 莫队算法或者说块状数组 其实都是有点优化的暴力
    CSU OJ PID=1514: Packs 超大背包问题,折半枚举+二分查找。
    运行时Runtime的API
    UIView的API
    UIControl的API
    UIScrollView的API
    使用KVO键值监听
  • 原文地址:https://www.cnblogs.com/wazy/p/7802910.html
Copyright © 2011-2022 走看看