一、可迭代对象 Iterable
Python 中能够使用for循环遍历,逐一返回其成员的对象称为可迭代对象,其中包括:
序列类型:如ist、str、tuple
非序列类型:dict、set等
# 通过Iterable来判断结果为True
from collections.abc import Iterable
li = [1, 2, 3]
st = 'python'
dic = {'name': 'python'}
tup = (1, 2, 3)
se = {1, 2, 3}
print(isinstance(li, Iterable))
print(isinstance(st, Iterable))
print(isinstance(dic, Iterable))
print(isinstance(tup, Iterable))
print(isinstance(se, Iterable))
运行结果:
True
True
True
True
True
如果自己创建一个可迭代对象需要遵循迭代协议,即对象必须包含__iter__()方法,那么就是一个可迭代对象,如下:
from collections.abc import Iterable
class MyClass():
def __iter__(self):
pass
if __name__ == "__main__":
m = MyClass()
print(isinstance(m, Iterable))# 判断是否为可迭代对象
运行结果:
True
而另一种特殊方法__getitem__()也可以让对象实现可迭代功能,但需要注意的是虽然称为可迭代对象,但不是Iterable类型,如下:
class MyClass2():
lis = [1, 2, 3]
def __getitem__(self, item):
return self.lis[item]
if __name__ == "__main__":
m2 = MyClass2()
for i in m2: #支持可迭代操作
print(i)
print(isinstance(m, Iterable))# 不是Iterable类型
运行结果:
1
2
3
False
可迭代对象:
1.实现了__iter__()方法的任意对象
2.实现了序列语义的__getitem__()方法的任意对象
二、迭代器 Iterator
迭代器继承于可迭代对象,所以继承了__iter__()方法,而迭代器自己也实现了一个__next__()方法,所以一个对象包含__iter__()、__next__两个方法,就称其为迭代器。
from collections.abc import Iterator
class MyClass():
def __iter__(self):
pass
def __next__(self):
pass
if __name__ == "__main__":
m = MyClass()
print(isinstance(m, Iterator))
运行结果:
True
所有的迭代器都是可迭代对象,因为迭代器继承于可迭代对象,而可迭代对象不一定是迭代器如下:
from collections.abc import Iterator
li = [1, 2, 3]
print(isinstance(li,Iterator))
运行结果:
False
而所有的可迭代对象都可以通过内置函数iter()转换为迭代器:
from collections.abc import Iterator
li = [1, 2, 3]
li = iter(li)
print(isinstance(li, Iterator))
运行结果:
True
获取迭代器中的元素可以通过内置方法next()或者对象的__next__()方法:
li = [1, 2, 3]
li = iter(li)
print(next(li))
print(next(li))
print(li.__next__())
运行结果:
1
2
3
当迭代器中的所有数据迭代完以后,继续取值则会引发StopIteration异常
print(li.__next__())
结果:
StopIteration
再来看下迭代器中的常用方法:
li = [1, 2, 3]
li = iter(li)
print(dir(li))
运行结果:
['__class__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__iter__', '__le__', '__length_hint__', '__lt__', '__ne__', '__new__', '__next__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__setstate__', '__sizeof__', '__str__', '__subclasshook__']
__length_hint__获取迭代器中内部元素的长度:
li = [1, 2, 3]
li = iter(li)
print(li.__length_hint__())
运行结果:
3
__setstate__设置迭代的起始位置:
li = [1, 2, 3]
li = iter(li)
li.__setstate__(1) # 设置从索引为1的位置开始获取
print(next(li))
运行结果:
2
三、生成器 Generator
继承于迭代器,相对于迭代器多了send,throw,close方法
1.生成式表达式:
from collections.abc import Generator
# 生成器表达式
g = (i for i in range(10))
# 判断是否为生成器
print(isinstance(g,Generator))
# 使用next()生成数据
print(next(g))
print(next(g))
print(next(g))
运行结果:
True
0
1
2
2.生成器函数。
如下:
包含yield关键字的函数为生成器函数,执行完后其返回结果是生成器对象,而并没有执行函数体
def fun():
print("TEST")
yield
print(fun())
运行结果:
# 生成器对象
<generator object fun at 0x000001D869961DD0>
而执行函数体的前提需要先执行next()方法,如下:next()是有惰性的,调用一次走一次,而遇到yield会停止,但不会结束函数。
def fun():
print("TEST")
yield
print("TEST_01")
yield
rs = fun()
next(rs)
next(rs)
运行结果:
TEST
TEST_01
当yield有返回值时:
def fun():
print("TEST")
yield '我是返回值1'
print("TEST_01")
yield '我是返回值2'
g = fun() # 生成生成器对象
print(next(g))
print(next(g))
运行结果:
TEST
我是返回值1
TEST_01
我是返回值2
再来看一个例子:
def fun():
for i in range(4):
yield i
g = fun() # 生成生成器对象
print(next(g))
print(next(g))
print(next(g))
print(next(g))
运行结果:
0
1
2
3
2.send方法:用于生成器内部数据交互,可以传递数据到生成器
def fun():
for i in range(4):
s = yield i
print(s)
g = fun()
next(g) # 需要注意执行send之前要通过next方法启动生成器
print(g.send('我传递进去后被yield接收赋值给了s'))
运行结果:
我传递进去后被yield接收赋值给了s
1