Python基础:18.迭代、可迭代对象、迭代器与生成器

一、迭代

通过for循环来遍历list、tuple或char,称为迭代

list1 = [1,2,3,4,5,6,7,8,9]
tuple1 = (1,2,3,4,5,6)
char1 = ‘python‘
for i in list1[0:2]:
    print(i)
for i in tuple1[0:2]:
    print(i)
for i in char1[0:2]:
    print(i)

1
2
1
2
p
y

dict默认是以key进行迭代。如果要迭代value,可以用for value in dict.values()。同时迭代key和value,可以用for k, v in d.items()

dict1 = {1:‘python‘,
        2:‘java‘,
        3:‘c++‘}
for key in dict1:   # 不一定非要用key这个变量,一种规范
    print(key)
for value in dict1.values():  # 注意values和()易写漏
    print(value)
for k,v in dict1.items():
    print(k,v)

1
2
3
python
java
c++
1 python
2 java
3 c++

二、可迭代对象(Iterable)

能用for循环进行迭代的对象就是可迭代对象
判断一个对象是可迭代对象的方法:通过collections.abc模块的Iterable类型判断
可迭代的对象:str,list,tuple,dict,set,文件对象

from collections.abc import Iterable
print(isinstance(‘abc‘, Iterable)) # str是否可迭代
print(isinstance(123, Iterable))   # 整数是否可迭代

True
False

如果要给list加下标,可以用Python内置的enumerate函数可以把一个list变成索引-元素对,这样就可以在for循环中同时迭代索引和元素本身

for i, value in enumerate([‘A‘, ‘B‘, ‘C‘]):
     print(i, value)

0 A
1 B
2 C

可迭代对象有内置iter()函数,可以将可迭代对象转为迭代器

三、迭代器(Iterator)

迭代器指的是迭代取值的工具,每次调用迭代器会返回自身的下一个元素,它表示的是一个数据流,可以看做是一个有序序列,但不能提前知道序列长度,只有在需要返回下一个数据时它才会计算。所以Iterator的计算是惰性的,和列表等集合数据类型不同

迭代器必须有两个基本的方法:iter() 和 next()
iter()将可迭代对象转变为迭代器
next()可以输出迭代器的下一个元素

从类角度讲,任何实现了__iter__()和__next__()方法的对象都是迭代器
为了防止出现无限循环的情况,StopIteration 异常用于标识迭代的完成,没有数据时抛出StopIteration异常,这并不是错误,只是提醒迭代完成

list1 = [1,2,3]
iter1 = iter(list1)  # 将列表转为迭代器
print(next(iter1))   # 输出迭代器下一个元素
print(next(iter1))
print(next(iter1))   
print(next(iter1))

1
2
3

StopIteration                             Traceback (most recent call last)

<ipython-input-16-8b77bc1ee74a> in <module>()
      4 print(next(iter1))
      5 print(next(iter1))
----> 6 print(next(iter1))


StopIteration: 
list1 = [1,2,3]
iter1 = iter(list1)  # 将列表转为迭代器
for i in iter1:      # 也常用for循环遍历迭代器内容
    print(i)

1
2
3

迭代器一定是可迭代对象,但可迭代对象不一定是迭代器,如list、dict、str等是Iterable但不是Iterator,需要经过iter()函数转换
常用的列表生成式就是迭代器
可以用collections.abc模块的Iterator类型判断一个对象是否是Iterator对象

from collections.abc import Iterable,Iterator
list1 = [1,2,3]
iter1 = iter(list1)  # 将列表转为迭代器
print(isinstance(list1, Iterable))
print(isinstance(list1, Iterator))  # 列表不是迭代器
print(isinstance(iter1, Iterable))
print(isinstance(iter1, Iterator))
print(isinstance((x for x in range(10)), Iterator))  # 列表生成式是迭代器

True
False
True
True
True

for循环本质就是基于迭代器:for 循环在处理这些数据前,会调用 iter() 方法,将这些数据转化为一个迭代器,然后调用迭代器的 next() 方法,并捕获StopIteration异常,也就实现了遍历完所有数据就会结束,并不会抛出这个异常
所以从for循环的角度,但凡可以被for循环取值的对象就是可迭代对象

迭代器的优缺点:
优点:1、提供了一种通用不依赖索引的迭代取值方式;2、同一时刻在内存中只存在一个值,更节省内存
缺点:1、取值不如按照索引的方式灵活,不能取指定的某一个值,只能往后取,不能往前取;2、无法预测迭代器的长度

四、生成器(Generator)

迭代器解决了特大序列占内存的问题,但当生成序列的算法较为复杂时,需要一个能更简介code的迭代器,而不是一直定义类,这就有了生成器(个人理解)

在 Python 中,使用了yield的函数被称为生成器,生成器本质上也是迭代器

generator和函数的执行流程不一样。函数是顺序执行,遇到return语句或者最后一行函数语句就返回。而变成generator的函数,在每次调用next()的时候执行,遇到yield语句返回,再次执行时从上次返回的yield语句处继续执行

需要给生成器设置一个条件来退出循环,不然就会无限产生内容出来

所以,生成器仅仅保存了一套生成数值的算法,并且没有让这个算法现在就开始执行,而是什么时候调它,它什么时候开始计算一个新的值,并返回

def fib(max):   # 斐波那契数列
    n, a, b = 0, 0, 1
    while n < max:
        yield b           # 遇到yield语句函数返回
        a, b = b, a + b   # 再次执行的时候从此执行
        n = n + 1
        
g = fib(6)
print(type(fib))   # fib是一个特殊函数,仍然是一个函数
print(type(g))     # 将该函数赋给一个对象,这个对象成了generator
for i in g:       # 迭代得到生成器元素
    print(i)       # 拿不到函数的return返回值

<class ‘function‘>
<class ‘generator‘>
1
1
2
3
5
8

值得注意的是,要想得到函数的return返回值,必须捕获StopIteration错误,返回值包含在StopIteration的value中。而若只使用for循环或者list()函数,python并不会抛出这个异常,所以需要使用while循环加上next()函数。因此,编写和应用生成器时,看是否需要返回值,来选择用for/list()还是next()

def fib(max):   # 斐波那契数列
    n, a, b = 0, 0, 1
    while n < max:
        yield b           # 遇到yield语句函数返回
        a, b = b, a + b   # 再次执行的时候从此执行
        n = n + 1
    return ‘done‘
g = fib(6)
while True:
    try:
        print(next(g))
    except StopIteration as e:   # 捕获StopIteration错误
        print(‘Generator return value:‘, e.value) # 返回值在异常的value中
        break  # 不加break,便会一直打印返回值

1
1
2
3
5
8
Generator return value: done

另外,只要把一个列表生成式的[]改成(),也能创建一个generator

g = (x * x for x in range(10))
type(g)

generator

迭代器和生成器都常被用于使用list()函数来生成列表
在写接受任意序列类型(列表、元组、N维数组),甚至是一个迭代器的函数时,可以先检查这个对象是否是列表,如果不是就将其转为列表

from collections.abc import Iterable

x = (1,2,3)
if not isinstance(x,list) and isinstance(x,Iterable):
    x = list(x)
print(x)

[1, 2, 3]

Python基础:18.迭代、可迭代对象、迭代器与生成器

上一篇:SQL Server存储过程中使用表值作为输入参数示例


下一篇:LeetCode 977 有序数组平方的排序