python可迭代遍历的数据类型 python可迭代对象_生成器


一、可迭代对象 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__()方法,那么就是一个可迭代对象,如下:

python可迭代遍历的数据类型 python可迭代对象_迭代_02

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

python可迭代遍历的数据类型 python可迭代对象_生成器_03


迭代器继承于可迭代对象,所以继承了__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方法

python可迭代遍历的数据类型 python可迭代对象_迭代_04


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