zoukankan      html  css  js  c++  java
  • Python全栈开发之4、迭代器、生成器、装饰器

    一、迭代器

    1、为何要有迭代器?

    对于序列类型:字符串、列表、元组,我们可以使用索引的方式迭代取出其包含的元素。但对于字典、集合、文件等类型是没有索引的,若还想取出其内部包含的元素,则必须找出一种不依赖于索引的迭代方式,这就是迭代器

    2、什么是可迭代对象?

    可迭代对象指的是内置有__iter__方法的对象,即obj.__iter__,如下
    'hello'.__iter__     #字符串
    (1,2,3).__iter__   #元组
    [1,2,3].__iter__   #列表
    {'a':1}.__iter__   #字典
    {'a','b'}.__iter__  #集合
    open('a.txt').__iter__  #文件

    3、什么是迭代器?

    可迭代对象执行obj.__iter__()得到的结果就是迭代器对象
    而迭代器对象指的是即内置有__iter__又内置有__next__方法的对象
    但是,listdictstr等可迭代对象并没有__next__()方法,所以它不是迭代器
    可以把使用iter()函数把
    listdictstr等可迭代对象变成迭代器
    from collections import Iterator
    
    a=isinstance([],Iterator)
    b=isinstance((),Iterator)
    c=isinstance({},Iterator)
    d=isinstance('abc',Iterator)
    e=isinstance((i for i in range(10)),Iterator)
    f=isinstance(100,Iterator)
    print(a)
    print(b)
    print(c)
    print(d)
    print(e)
    print(f)
    
    输出:
    False
    False
    False
    False
    True
    False
    使用isinstance()判断一个对象是否是可迭代对象
    str1='hello'    #字符串
    tuple1=(1,2,3) #元组
    list1=[1,2,3]  #列表
    dict1={'a':1}  #字典
    set1={'a','b'} #集合
    
    #使用iter()方法把可迭代对象变成迭代器
    iter_str=iter(str1)
    iter_tuple=iter(tuple1)
    iter_list=iter(list1)
    iter_dict=iter(dict1)
    iter_set=iter(set1)
    
    print(iter_str.__next__())
    print(iter_tuple.__next__())
    print(iter_list.__next__())
    print(iter_dict.__next__())
    print(iter_set.__next__())
    把list、dict、str等可迭代对象变成迭代器

    4、for循环

    #基于for循环,我们可以完全不再依赖索引去取值了
    dic={'a':1,'b':2,'c':3}
    for k in dic:
        print(dic[k])
    
    #for循环的工作原理
    
    #1:执行in后对象的dic.__iter__()方法,得到一个迭代器对象iter_dic
    #2: 执行next(iter_dic),将得到的值赋值给k,然后执行循环体代码
    #3: 重复过程2,直到捕捉到异常StopIteration,结束循环

    5、迭代器的缺点

    #优点:
      - 提供一种统一的、不依赖于索引的迭代方式
      - 惰性计算,节省内存
    #缺点:
      - 无法获取长度(只有在next完毕才知道到底有几个值)
      - 一次性的,只能往后走,不能往前退

    二、生成器

     1、什么是生成器?

    可以理解为一种数据类型、这种数据类型实现了迭代器协议(其他的数据类型需要调用自己内置的__iter__()方法才可以),所以生成器就是可迭代对象。

    2、生成器在Python中的表现形式

    1、生成器函数
    常规函数定义、但是是使用yield语句而不是使用return返回结果
    yield语句一次返回一个结果、在每个结果中间挂起函数的状态
    
    2、生成器表达式
    类似于列表推导、但是生成器返回按需产生一个对象而不是一次构建一个结果列表

    3、列表生成式

    现在有一个需求,需要把列表[0,1,2,3,4,5,6,7,8,9]里的每个元素都加1,怎么实现?有以下几种方式:
    list1=[0,1,2,3,4,5,6,7,8,9]
    
    for index,i in enumerate(list1):
        list1[index]=i+1
        
    print(list1)     #原值修改
    
    或者
    
    a=[]
    for i in range(10):
        a.append(i*2)
    print(a)

    列表生成式写法

    num_list = [ i*2 for i in range(10) ]
    
    #或者赋值
    num_list = [ "数字%s"%i  for i in range(10) ]
    print(num_list)
    
    #输出:
    ['数字0', '数字1', '数字2', '数字3', '数字4', '数字5', '数字6', '数字7', '数字8', '数字9']
    
    #结合三元表达式
    
    num_list = [ "数字%s"%i  for i in range(10) if i > 5]
    
    print(num_list)
    #输出:
    ['数字6', '数字7', '数字8', '数字9']

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

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

    在Python中,这种一边循环一边计算的机制,称为生成器:generator。

    要创建一个generator,有很多种方法。第一种方法很简单,只要把一个列表生成式的[]改成(),就创建了一个生成器:

    num_list = ("数字%s"%i  for i in range(10) if i > 5)
    
    print(num_list.__next__())
    print(num_list.__next__())
    print(num_list.__next__())
    
    #输出:
    数字6
    数字7
    数字8

    4、yield生成器函数

    只要函数中存在yield,这个函数就是一个生成器函数

    yield功能:1、相当于return一个返回值。2、保存函数的状态,以便下次从它离开的地方执行

    def test():
    
        yield 1
        yield 2
        yield 3
        yield 4
    
    num=test()
    print(num.__next__())
    print(num.__next__())
    print(num.__next__())
    print(num.__next__())
    #输出:1
    #     2
    #     3
    #     4
    def fib(max):
        n,a,b=0,0,1
        while n<max:
            # print(b)
            yield b
            a,b=b,a+b
            n=n+1
    
    gen=fib(10)
    for i in gen:
        print(i)
    yield实现斐波拉契数列
    import time
    def consumer(name):
        print("%s准备吃包子了"%name)
        while True:
            baozi=yield
    
            print('包子[%s]来了,被%s吃了'%(baozi,name))
    
    
    # c1=consumer('lily')
    # c1.__next__()
    #
    # c1.send('韭菜')
    
    def producer(name):
        c=consumer('A')
        c2=consumer('B')
        c.__next__()
        c2.__next__()
        print('%s开始做包子了'%name)
        for i in range(10):
            time.sleep(1)
            print('做了两个包子')
            c.send(i)
            c2.send(i)
    
    producer('Tom')
    通过yield实现在单线程的实现并发运算
    #yield相当于return控制的是函数的返回值
    #x=yield的另外一个特性是,接收send()传过来的值赋值给yield
    
    def func():
        print("yield来啦")
    
        name=yield
    
        print("yield接收send传参-%s"%name)
        yield 2
        print("下一步yield执行啦")
    
    
    test=func()
    
    print(test.__next__())  # 这一步打印的yield返回值是None
    
    res=test.send('Tom')  #把Tom传给yield然后赋值给name,执行到yield 2返回  send相当于一次next操作
    
    print(res)
    yield-send()方法

     三、装饰器

    定义:装饰器本质上是一个函数

    功能:就是为其他函数添加附加功能

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

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

    #实现装饰器的知识:
    
    #1.函数即变量 
    
    #2.高阶函数:满足下面两个条件
    
            #a: 把一个函数名当做实参传给另外一个函数  (在不修改被装饰函数源代码的情况下为其添加功能)
    
            #b: 返回值中包含函数名(不改变函数的调用方式)
    
    #3.嵌套函数
    
    #高阶函数+嵌套函数+闭包 =装饰器
    import time
    
    def timer(func):
        def deco(*args,**kwargs):
            start_time=time.time()
            func(*args,**kwargs)       #会往上一级找
            end_time=time.time()
            print('the func run time is %s'%(end_time-start_time))
        return deco
    @timer
    def test1(name):
        time.sleep(3)
        print('in the test1')
        print(name)
    @timer
    def test2():
        time.sleep(3)
        print('in the test2')
    
    #test1=timer(test1)
    #test2=timer(test2)
    
    
    
    test1('sunhao')
    test2()
    装饰器例子
    import time
    
    def timmer(func):  
        def wrapper():
            start_time=time.time()
            result=func()    #拿到func函数的返回值
            stop_time=time.time()
            print('the func run time is %s'%(stop_time-start_time))
         return result    #再返回
        return wrapper
    
    
    def test():
        time.sleep(1)
        print('in the test1')
    
    
    res=timmer(test)   #返回的是wrapper的地址   timmer(test) 相当于@timmer
    
    res() #执行的是wrapper函数
    
    #把timmer(test)赋值给test,再执行test(),就没修改被装饰的函数的调用方式 
    import time
    def timmer(func):
        def wrapper(*args,**kwargs):
            start_time=time.time()
            res=func(*args,**kwargs)
            stop_time=time.time()
            print('run time is %s' %(stop_time-start_time))
            return res
        return wrapper
    
    @timmer #相当于foo=timmer(foo)
    def foo():
        time.sleep(3)
        print('from foo')
    
    
    foo()
    无参装饰器
    user_list=[{'name':'allen','password':'123456'},
               {'name':'lucy','password':'123456'},
               {'name':'lily','password':'123456'}
               ]
    
    current_user={'username':None,'login':False}
    
    def auth_type(func):
    
        def wrapper(*args,**kwargs):
    
            if current_user['username'] and current_user['login']:
    
                ret = func(*args,**kwargs)
                return ret
    
            username=input("请输入用户名:").strip()
            password=input("请输入密码:").strip()
            for name in user_list:
    
                if name['name']== username and name['password'] == password:
                    current_user['username']=username
                    current_user['login']=True
    
                    ret = func(*args, **kwargs)
                    return ret
    
            else:
                print("用户名密码错误")
    
    
        return wrapper
    
    @auth_type
    def index(name):
        print("欢迎来%s购物商城"%name)
    
    @auth_type
    def shopping():
    
        print("shopping 吧")
    
    
    index('京东')
    shopping()
    登录认证模拟session
    user_list=[{'name':'allen','password':'123456'},
               {'name':'lucy','password':'123456'},
               {'name':'lily','password':'123456'}
               ]
    
    current_user={'username':None,'login':False}
    
    def outer(auth_type):
    
    
        def auth_func(func):
    
            def wrapper(*args,**kwargs):
                print("认证类型是%s"%auth_type)
                
                if auth_type =="file":
                    if current_user['username'] and current_user['login']:
    
                        ret = func(*args,**kwargs)
                        return ret
    
                    username=input("请输入用户名:").strip()
                    password=input("请输入密码:").strip()
                    for name in user_list:
    
                        if name['name']== username and name['password'] == password:
                            current_user['username']=username
                            current_user['login']=True
    
                            ret = func(*args, **kwargs)
                            return ret
    
                    else:
                        print("用户名密码错误")
    
                elif auth_type =='mysql':
    
                    ret = func(*args, **kwargs)
                    return ret
    
    
            return wrapper
    
        return auth_func
    
    
    @outer(auth_type='file')  #auth_func=outer(auth_type='filedb')
    def index(name):
        print("欢迎来%s购物商城"%name)
    
    @outer(auth_type='mysql')
    def shopping():
    
        print("shopping 吧")
    
    
    index('京东')
    shopping()
    有参装饰器
  • 相关阅读:
    关于API微服务网关
    适用于企业的API管理平台
    简单的api测试
    Json,2020年api数据格式的Top 1
    API文档之团队协作
    如何进行API测试以提高程序质量
    API接口也要监控?
    春招实习_腾讯 wxg 一面 3.27 15:00
    春招实习_腾讯一面 & 二面_3.13
    春招实习_阿里一面
  • 原文地址:https://www.cnblogs.com/sunhao96/p/7656453.html
Copyright © 2011-2022 走看看