• python笔记09-----装饰器,生成器,迭代器


    1.装饰器

    定义:本质是函数,(装饰其他函数)就是为其他函数添加附加功能

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

       2.不能修改被装饰的函数的调用方式

    实现装饰器的知识储备:

      1.      函数即“变量”

      2.      高阶函数

               a.      把一个函数名当做实参传给另一个函数(在不修改被装饰函数源代码的情况下为期添加功能)

               b.      返回值中包含函数名(不修改函数的调用方式)

      3.      嵌套函数

      4.      高阶函数+嵌套函数=装饰器

    1.1 实现简单的装饰器

     1 def outer(fun):
     2     def warper():
     3         print("outer 1")
     4         fun()                  #相当于把下边两个函数当参数传入进来
     5         print("outer 3")
     6     return warper
     7 
     8 @outer
     9 def test1():
    10     print("test1 2")
    11 @outer
    12 def test2():
    13     print("test2 2")           
    14 test1()
    15 test2()
    -----------------结果----------------- 16 outer 1 17 test1 2 18 outer 3 19 outer 1 20 test2 2 21 outer 3

    1.2 装饰器传参

    简单难度的传参

     1 def outer(fun):
     2     def warper(*args,**kwargs):
     3         print("加的第一个功能在函数之前")
     4         fun(*args,**kwargs)
     5         print("加的第二个功能在函数之后")
     6     return warper
     7 
     8 @outer
     9 def test1(*args,**kwargs):
    10     print(args,kwargs)
    11     return
    12 
    13 
    14 test1(123,"waa","yyy",name="wsy",Age=18)
    15 ----------------结果----------------------
    16 加的第一个功能在函数之前
    17 (123, 'waa', 'yyy') {'name': 'wsy', 'Age': 18}
    18 加的第二个功能在函数之后

    中等难度的传参

    加入time模块记录执行时间

    import time
    
    def timer(func):
    
        def deco(*args,**kwargs):
            start = time.time()
            print("装饰器:功能1")
            func(*args,**kwargs)
            print("装饰器:功能2")
            end = time.time()
            print("func run time is %s" %(end - start))
        return deco
    
    @timer
    def test1():
        time.sleep(1)
        print("in the test1")
    @timer
    def test2(*args,**kwargs):
        time.sleep(1)
        print("in the test1",args,kwargs)
    
    test1()
    test2(1,2,3,4,name="wsy",age=20)
    --------------------结果------------------------
    装饰器:功能1
    in the test1
    装饰器:功能2
    func run time is 1.0000572204589844
    装饰器:功能1
    in the test1 (1, 2, 3, 4) {'name': 'wsy', 'age': 20}
    装饰器:功能2
    func run time is 1.0000572204589844

    多重认证  第一个页面认证成功直接进入其他两个页面

     1 user,passwd = "wsy","123"
     2 def auth(auth_type):
     3     print("auth func:",auth_type)
     4     def outer_wrapper(func):
     5         def wrapper(*args,**kwargs):
     6             print("wrapper func args:", *args,**kwargs)
     7             if auth_type == "local": # 如果装饰器参数是local 就
     8                 username = input("Username:").strip() # 输入用户名
     9                 password = input("Password:").strip() # 输入密码
    10                 if user == username and passwd == password: # 判断如果正确
    11                     print("33[32;1mUser has passwd authentication33[0m")
    12                     res = func(*args,**kwargs) #from home
    13                     print("-------after authenticaion")
    14                     return res
    15                 else:
    16                     exit("33[31;1mInvalid username or password 33[0m")
    17             elif auth_type == "ldap": # 如果装饰器参数是ldap
    18                 print("hehe")
    19         return wrapper
    20     return outer_wrapper
    21 
    22 
    23 def index():
    24     print("welcome to index page")
    25 
    26 @auth(auth_type="local")
    27 
    28 def home():
    29     print("welcome to home page")
    30     return "from home"
    31 @auth(auth_type="ldap")
    32 def bbs():
    33     print("welcome to bbs page")
    34 index()
    35 print (home())
    36 bbs()
    37 -----------------------结果-----------------------
    38 auth func: local
    39 auth func: ldap
    40 welcome to index page
    41 wrapper func args:
    42 Username:wsy
    43 Password:123
    44 User has passwd authentication
    45 welcome to home page
    46 -------after authenticaion
    47 from home
    48 wrapper func args:
    49 hehe

     2.生成器

    生成器

    通过列表生成式,我们可以直接创建一个列表。但是受到内存限制,列表容量肯定是有限的。而且,创建一个包含100万个元素的列表,不仅占用很大的存储空间,如果我们仅仅需要访问前面几个元素,那后面绝大多数元素占用的空间都白白浪费了。

    所以,如果列表元素可以按照某种算法推算出来,那我们是否可以在循环的过程中不断推算出后续的元素呢?这样就不必创建完整的list,从而节省大量空间,在py中,这种一遍循环一遍计算的机制,称为生成器

    终端命令行执行
    
    >>> a = [1,2,3]
    
    >>> [i*2 for i in range(10)]
    
    -----------------输出结果-----------------
    
    [0, 2, 4, 6, 8, 10, 12, 14, 16, 18]
    列表生成器
    终端执行:
    >>> ( i*2 for i in range(10))
    -------------------输出结果------------------------
    
    <generator object <genexpr> at 0x00000000021859E8>
    
    
    >>>b = ( i*2 for i in range(10))
    
    >>> for i in b:
    
    ...     print(i)
    -------------------输出结果-------------------------
    
    0
    
    2
    
    4
    
    6
    
    8
    
    10
    
    12
    
    14
    
    16
    
    18
    range

    生成器 只有在调用时才会生成相应的数据       

    只记住当前位置

    只有一个__next__()方法

     1 a = (i*2 for i in range(100))
     2 print(a.__next__())
     3 print(a.__next__())
     4 print(a.__next__())
     5 print(a.__next__())
     6 ---------------输出结果-------------------
     7 0
     8 2
     9 4
    10 6

    我们创建了一个generator(生成器)后,基本上永远不会调用next(),而是通过for循环来迭代它,并且不需要关心StopIteration的错误

    generator(生成器)非常强大,如果推算的算法比较复杂,用列斯列表生成式的for循环无法实现的时候,还可以用函数来实现

    2.1 斐波那契数列

    菲波纳契数列,除第一个和第二个数外,任意一个数都可由前两个数相加得到

     1 def fib(max):
     2     n, a, b = 0, 0, 1
     3     while (n < max):
     4         print(b)
     5         a, b = b, a+b
     6         n += 1
     7 
     8 fib(10)
     9 ---------------------------------------
    10 1
    11 1
    12 2
    13 3
    14 5
    15 8
    16 13
    17 21
    18 34
    19 55

    2.2 yield

     1 def fib(max):
     2     n,a,b = 0,0,1
     3     while (n < max):
     4         yield b
     5         a,b = b, a+b
     6         n += 1
     7 f = fib(10)
     8 for i in range(10):
     9     print(f.__next__())
    10 --------------输出结果-----------------
    11 1
    12 1
    13 2
    14 3
    15 5
    16 8
    17 13
    18 21
    19 34
    20 55

    2.3 yield 实现单线程并行

     1 import time
     2 def consumer(name):
     3     while True:
     4         baozi = yield
     5         print("包子[%s]来了,被[%s]吃了" %(baozi,name))
     6 
     7 
     8 c = consumer("wsy")
     9 c.__next__()
    10 
    11 def producer(name):
    12     c = consumer('')
    13     c2 = consumer('')
    14     c.__next__()
    15     c2.__next__()
    16     print("开始吃")
    17     for i in range(10):
    18         time.sleep(1)
    19         print("做了1个包子,分两半")
    20         c.send(i)
    21         c2.send(i)
    22 producer("wsy")
    23 ---------------------------结果------------------------
    24 开始吃
    25 做了1个包子,分两半
    26 包子[0]来了,被[猫]吃了
    27 包子[0]来了,被[狗]吃了
    28 做了1个包子,分两半
    29 包子[1]来了,被[猫]吃了
    30 包子[1]来了,被[狗]吃了
    31 做了1个包子,分两半
    32 包子[2]来了,被[猫]吃了
    33 包子[2]来了,被[狗]吃了
    34 做了1个包子,分两半
    35 包子[3]来了,被[猫]吃了
    36 包子[3]来了,被[狗]吃了
    37 做了1个包子,分两半
    38 包子[4]来了,被[猫]吃了
    39 包子[4]来了,被[狗]吃了
    40 做了1个包子,分两半
    41 包子[5]来了,被[猫]吃了
    42 包子[5]来了,被[狗]吃了
    43 做了1个包子,分两半
    44 包子[6]来了,被[猫]吃了
    45 包子[6]来了,被[狗]吃了
    46 做了1个包子,分两半
    47 包子[7]来了,被[猫]吃了
    48 包子[7]来了,被[狗]吃了
    49 做了1个包子,分两半
    50 包子[8]来了,被[猫]吃了
    51 包子[8]来了,被[狗]吃了
    52 做了1个包子,分两半
    53 包子[9]来了,被[猫]吃了
    54 包子[9]来了,被[狗]吃了
    吃包子例子

     3.迭代器

    我们已经知道,可以直接作用于for循环的数据类型有一下几种:

    1.集合数据类型,如list,tuple,dict,set,str等

    2.生成器,包括生成器和带yield的generator function

    这些可以直接作用于for循环的对象统称为可迭代对象:Iterable

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

     1 命令行
     2 >>> from collections import Iterable
     3 >>> isinstance([],Iterable)
     4 True
     5 >>> isinstance({},Iterable)
     6 True
     7 >>> isinstance('abc',Iterable)
     8 True
     9 >>> isinstance((x for x in range(10)),Iterable)
    10 True
    11 >>> isinstance(100,Iterable)
    12 False
    判断是否为iterable对象

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

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

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

    #结论:生成器一定是迭代器 迭代器不一定是生成器

    生成器都是Iterator(迭代器)对象,但list,dict,str虽然是iterable(可迭代)却不是Iterator(迭代器)

    把list,dict,str等Iterable变成Iterator可以使用iter()函数:

     1 >>> a
     2 [1, 2, 3]
     3 >>> iter(a)
     4 <list_iterator object at 0x0000000002150898>
     5 >>> b = iter(a)
     6 >>> b.__next__()
     7 1
     8 >>> b.__next__()
     9 2
    10 >>> b.__next__()

    只要有next()函数 一定是迭代器

     

  • 相关阅读:
    zabbix系列 ~ mongo监控相关
    zabbix系列 ~ 自动监控多实例功能
    mysql 查询优化 ~ 多表查询改写思路
    MGR架构~高可用架构细节的梳理
    mysql 半同步复制~ 整体概述与改进
    android 单独编译某个模块
    Nginx使用
    21天学通C++学习笔记(九):类和对象
    1. 个人经验总结
    C++视频教程学习笔记
  • 原文地址:https://www.cnblogs.com/wsy1030/p/9015817.html
Copyright © 2020-2023  润新知