python3之迭代器和生成器

迭代器


迭代器的定义:

  • 迭代器是访问可迭代对象的工具
  • 迭代器是指用iter(obj)函数返回的对象(或实例)
  • 迭代器可以用next(it)函数获取可迭代对象的数据

用在迭代器的函数有两个,分别是iter和next

在了解迭代器之前先了解一下什么是可迭代对象:

  • 表面来看,只要可以用 for…in…进行遍历的对象就是可迭代对象

例如:list列表、tuple元组、str字符串等都是可迭代对象

  1. iter(iterable)从可迭代对象中返回一个迭代器,iterable必须是能够提供一个迭代器的对象
  2. next(iterator)从迭代器iterator中获取下一个记录,如果无法获取了,则触发stopIterator异常

说明:

  • 迭代器只能往前取值,不会后退
  • 用iter函数返回的是一个可迭代对象的迭代器

举个栗子:

L = [1, 3, 5, 7]  # 或 L = (1, 3, 5, 7)等可迭代对象都行 
it = iter(L)  # 让L提供一个能访问自己的迭代器
print(ext(it))  # 1 从迭代器中取值,让迭代器去获取L中的一个元素
print(ext(it))  # 3
print(ext(it))  # 5
print(ext(it))  # 7
print(ext(it))  # StopIteraotr 异常

当然这只是为了更直观的观察是怎么打印的

也可以使用循环遍历出结果

那么就引出了迭代的用处:

用迭代器可以依次访问可迭代对象的数据

示例:
    L = [1, 3, 5, 7]
    for i in L:
        print(i)   # 1 3 5 7

    以下用迭代器来访问L列表中的元素
    L = [1, 3, 5, 7]
    it = iter(L)  # 先拿到迭代器用it绑定
    while True:
        x = next(it)  # 获取一个数据并绑定x
        print(x)  # 1 3 5 7 

生成器


能够动态提供数据的对象,生成器对象也是可迭代对象,生成器也有两种表示方式:函数和表达式

函数:含有yield语句的函数,此函数被调用将返回一个生成器对象

注:yield翻译成产生(或生成)

yield用于def 函数中,目的就是将此函数作为生成器函数使用
yield用来生成数据,供迭代器和next(it)函数使用

生成器函数的声明:

  • 生成器函数调用return语句会触发一个StopIterator异常

举个小栗子:

题目:写一个生成器函数myeven(start, stop)
用来生成start到stop(不包含stop)结束的偶数并 存放在列表中

def myeven(start, stop):

    # 方法一
    # i = start + 1
    # while i < stop:
    #     yield i
    #     i += 2

    # 方法二
    # while start < stop:
    #     if start % 2 == 0:
    #         yield start
    #     start += 1

    # 方法三
    for i in range(start + 1, stop, 2):
        yield i


for x in myeven(1, 10):
    print(x)

L = [x ** 2 for x in myeven(1, 20)]
print(L)

解释以上代码:

只解释方法三即可:
先说说输入与输出:
在myeven(start, stop)中,如果start = 10,stop = 20,则输出的应该是10,12,14,16,18,也就是输出start到stop之间的偶数,但是不包括stop
再说说生成器函数
这里写图片描述
生成器是现用现生成,即可以理解为,你让我去干一件事,我干完就完事,你再让我干另一件事,我再去干,而不是说你给我一个清单让我一次性的做完清单上的事。

图片上的函数外的for循环是多次调用myeven函数,把1和10传进去,然后函数内部的for循环则循环生成一个数,但每次循环都会返回给外层循环打印出这个数,然后继续内部循环,再返回,…,这样一直调用到不满足条件为止
生成器表达式:

语法:
(表达式 for 变量 in 可迭代对象 [if 真值表达式])
作用:
用推导式形式创建一个新的生成器

说明:
if 子句可以省略

示例:
    gen = (x**2 for x in range(1, 5))
    it = iter(gen)
    print(next(it))  # 1
    print(next(it))  # 4
    print(next(it))  # 9
    print(next(it))  # 16
    print(next(it))  # StopIteration

生成器表达式和列表推导式的区别:

# 列表推导式
L = [2, 3, 5, 7]
L2 = [x**2+1 for x in L]  # 已经生成列表
it = iter(L2)
print((next(it)))  # 5
L[1] = 30  # 再改变L的值也不影响L2列表
print(next(it))  # 10


# 生成器表达式
L = [2, 3, 5, 7]
gen = (x**2+1 for x in L)  # 现用现生成,每次用只生成一个对应的值
it = iter(gen)
print((next(it)))  # 5
L[1] = 30  # 由于不是生成的列表,每次只生成一个值,所以这是先给变原列表对应的值,然后再做运算
print(next(it))  # 901

总结:生成器推导式是现用现生成,列表推导式是一次性生成静态数据

迭代工具函数:

生成一个个性化的可迭代对象

函数:

zip(iter1, [, iter[..]])

返回一个zip对象,此对象用于生成元组,此元组的每个数据来源于参数中的可迭代对象,当最小的可迭代对象不再提供数据时迭代结束

enumerate(iterable [, start])生成带索引的枚举对象,返回的迭代类型为索引-值对象(index-value)对,默认索引从0开始,也可以用start指定

zip示例:

    numbers = [10086, 10010, 10000, 95588]
    names = ['中国移动', '中国联通', '中国电信']
    for t in zip(numbers, names):
        print(t)

    for No, number, name in zip(range(1, 100), numbers, names):
        print('序号', No, name, '的客服电话是:', number)

打印结果:

(10086, '中国移动')
(10010, '中国联通')
(10000, '中国电信')
序号 1 中国移动 的客服电话是: 10086
序号 2 中国联通 的客服电话是: 10010
序号 3 中国电信 的客服电话是: 10000

enumerate示例:

    names = ['中国移动', '中国联通', '中国电信']

    for t in enumerate(names):
        print(t)

打印结果:

    #(0, '中国移动')
    #(1, '中国联通')
    #(2, '中国电信')

改变序号:

    for t in enumerate(names, 101):
        print(t)

打印结果:

    #(101, '中国移动')
    #(102, '中国联通')
    #(103, '中国电信')

不得不说zip是个很实用的家伙,据说用的挺多的,简单举个栗子:

numbers = [10086, 10010, 10000, 95588]
names = ['中国移动', '中国联通', '中国电信']

print(list(zip(numbers, names)))
print(tuple(zip(numbers, names)))
print(dict(zip(numbers, names)))
print(set(zip(numbers, names)))

打印结果:

[(10086, '中国移动'), (10010, '中国联通'), (10000, '中国电信')]
((10086, '中国移动'), (10010, '中国联通'), (10000, '中国电信'))
{10086: '中国移动', 10010: '中国联通', 10000: '中国电信'}
{(10086, '中国移动'), (10000, '中国电信'), (10010, '中国联通')}

尤其是字典,省去了不少功夫,一下搞定

本章暂时到这,是不是莫名的就结束了?没办法啦。。。

猜你喜欢

转载自blog.csdn.net/geek_xiong/article/details/81916526