• 14、迭代器协议、生成器、装饰器



    14.1、迭代器协议:

    1、迭代器协议是指:对象必须提供一个next方法,执行该方法要么返回对象中的下一项,要么就引起一个StopIteration异常,以终止次迭

    代,迭代器协议规定迭代只能往后走,不能往前退;

    2、可迭代对象是指:实现了迭代器协议的对象,可迭代对象只能遍历一次,使用可迭代对象比较省内存空间,通常使用__iter__和__next__实现;

    3、协议是一种约定,可迭代对象实现了迭代器协议,python内部工具(如:for,sum,min,max函数等)使用迭代器协议访问可迭代对象;

    4、字符串,列表,元组,字典,集合,文件对象、这些都不是可迭代对象,只不过for循环调用了他们内部的__iter__()方法,把他们变成了

    可迭代对象;

    5、可迭代对象用法:

    (1)查看函数可用的方法:

    print(dir(set))


    (2)示例:

    1)

    x='hello'

    iter_test=x.__iter__()

    # 遵循迭代器协议,生成可迭代对象

    print(iter_test)

    # <str_iterator object at 0x00000182D0132EB8>

    # 输出的是可迭代对象

    print(iter_test.__next__())

    print(next(iter_test))

    # next(iter_test)---->iter_test.__next__()

    print(iter_test.__next__())

    print(iter_test.__next__())

    print(iter_test.__next__())

    # print(iter_test.__next__())

    # 如果超过迭代的元素会引起StopIteration异常


    2)

    l=[1,2,3,4,5]

    diedai_l=l.__iter__()

    while True:

    try:

    print(diedai_l.__next__())

    except StopIteration:

    print('迭代完毕了,循环终止了')

    break


    3)

    dic={'a':1,'b':2}

    iter_d=dic.__iter__()

    print(iter_d.__next__())

    print(iter_d.__next__())


    4)

    f=open('告白气球','r',encoding='utf8')

    iter_f=f.__iter__()

    print(iter_f)

    # <_io.TextIOWrapper name='告白气球' mode='r+' encoding='utf8'>

    print(iter_f.__next__(),end='')

    print(iter_f.__next__(),end='')


    5)

    f=open('告白气球','r',encoding='utf8')

    for i in f:

    print(i,end='')


    6)

    l = [1, 2]

    print(sum(l))

    # sum(l.__iter__().next+l.__iter__().next)


    7)最终写法:

    l=[1,2,3]

    for i in l: #i_l=l.__iter_() i=i_l.__next__()

    print(i)


    14.2、生成器:

    1、生成器可以理解为一种数据类型,这种数据类型自动实现了迭代器协议(其它的数据类型需要调用自己内置的__iter__()方法来实现迭代器协

    议)所以生成器就是可迭代对象;

    2、语法上和函数类似:生成器函数和常规函数几乎是一样的,它们都是使用def语句进行定义,差别在于,生成器使用yield语句返回一个值,

    而常规函数使用return语句返回一个值;

    3、自动实现迭代器协议:对于生成器,Python会自动实现迭代器协议,以便应用到迭代背景中(如for循环,sum函数),由于生成器自动实现

    了迭代器协议,所以,我们可以调用它的next方法,并且在没有值可以返回的时候,生成器自动产生StopIteration异常;

    4、状态挂起:生成器使用yield语句返回一个值,yield语句挂起该生成器函数的状态,保留足够的信息,以便之后从它离开的地方继续执行;

    5、注意事项:生成器只能遍历一次

    6、使用生成器的优点:

    (1)优点一:生成器的好处是延迟计算,一次返回一个结果,也就是说,它不会一次生成所有的结果,这对于大数据量处理,将会非常有用;

    #列表解析

    sum([i for i in range(100000000)]) #内存占用大,机器容易卡死

    #生成器表达式

    sum(i for i in range(100000000)) #几乎不占内存

    (2)优点二:生成器还能有效提高代码可读性

    7、生成器的用法:

    (1)普通用法:

    def test():

    yield 1

    yield 2

    yield 3

    g = test()

    # 获取生成器对象

    print(g)

    # <generator object test at 0x0000025B4D0C97C8>

    print(g.__next__())

    print(g.__next__())

    print(g.__next__())


    (2)使用三元表达式创建生成器:

    1)三元表达的使用(三元表达式只有三元,没有四元):

    name = 'chang'

    res = 'cool' if name == 'chang' else 'so cool'

    print(res)


    test = [i for i in range(10) if i > 5]

    print(test)


    test_list = []

    for i in range(10):

    test_list.append(i)

    print(test_list)

    #等价于

    l = [i for i in range(10)]

    print(l)


    2)示例:

    laomuji = ('鸡蛋%s' % i for i in range(5))

    # 生成器表达式

    print(laomuji)

    # <generator object <genexpr> at 0x0000022CA82A97C8>

    print(laomuji.__next__())

    print(laomuji.__next__())

    print(next(laomuji))

    print(next(laomuji))

    print(next(laomuji))

    #等价于

    laomuji = ('鸡蛋%s' % i for i in range(5))

    for i in laomuji:

    print("鸡蛋%s" %i)


    14.3、装饰器:

    1、装饰器定义:本质就是函数,功能是为其他函数添加新功能

    2、装饰器需要遵循的原则:

    (1)不修改被装饰函数的源代码

    (2)为被装饰函数添加新功能后,不修改被修饰函数的调用方式

    3、实现装饰器知识储备:

    装饰器=高阶函数+函数嵌套+闭包( 在一个作用域里放入定义变量,相当于打了一个包)

    4、装饰器的用法:

    import time



    def timmer(func):

    def wrapper(*args, **kwargs):

    start_time = time.time()

    res = func(*args, **kwargs)

    # 运行的是cal函数

    stop_time = time.time()

    print('函数运行时间是%s' % (stop_time - start_time))

    return res


    return wrapper



    @timmer

    # 语法糖@

    # @timmer就相当于cal=timmer(cal),返回的是wrapper的地址,执行cal()就是在执行wrapper()

    # cal=timmer(cal)=wrapper

    def cal(l):

    res = 0

    for i in l:

    time.sleep(0.1)

    res += i

    return res



    res = cal(range(20))

    print(res)
























  • 相关阅读:
    你好,2021!
    庚子走,辛丑来,愿一切安好!
    花魂鸟魂总难留,鸟自无言花自羞
    熟悉的小胡同
    夜半听鼾声
    写在儿子22岁生日
    vue配置Azure Artifacts npm包源
    RabbitMQ出错:AMQP close-reason, initiated by Peer, code=530的解决办法
    .NET MVC存储图片到数据库的解决方案
    EF Core解决报错’EntityTypeBuilder未包含“ToTable”的定义‘的方法
  • 原文地址:https://www.cnblogs.com/LiuChang-blog/p/12317209.html
Copyright © 2020-2023  润新知