迭代(iteration)与可迭代(iterable)
迭代是一种操作;可迭代是对象的一种特性。
我们可以从一个对象中,逐个地获取元素,那么我们就说这个对象是「可迭代的」。
迭代器
迭代器是一种对象
迭代器抽象的是一个「数据流」,是只允许迭代一次的对象。对迭代器不断调用 next() 方法,则可以依次获取下一个元素;当迭代器中没有元素时,调用 next() 方法会抛出 StopIteration 异常。迭代器的 __iter__() 方法返回迭代器自身;因此迭代器也是可迭代的。
迭代器协议(iterator protocol)
Python 中的迭代器协议和 Python 中的 for 循环是紧密相连的。
# iterator protocol and for loop
for x in something:
print(x)
Python 处理 for 循环时,首先会调用内建函数 iter(something),它实际上会调用 something.__iter__(),返回 something 对应的迭代器。而后,for 循环会调用内建函数 next(),作用在迭代器上,获取迭代器的下一个元素,并赋值给 x。此后,Python 才开始执行循环体。
for循环内部操作
for循环中,会自动调用 iter()将我们要迭代的对象转化为可迭代对象,每次循环都会调用 .next() 方法获取新元素,当引发StopIteration错误的时候自动退出循环,这就for循环的内部操作。
Python 中的顺序类型,都是可迭代的(list, tuple, string)。其余包括 dict, set, file 也是可迭代的。对于用户自己实现的类型,如果提供了 iter() 或者 getitem() 方法,那么该类的对象也是可迭代的。
生成器、yield
表达式
调用过程
yield的核心在于冻结函数,一旦遇到,冻结这个函数;而return在于结束函数,一旦遇到,返回结果,函数整个退出,下次调用时重新开始执行。
生成器就是每次调用的时候返回一个对象,而不是一次性在内存中创建,从而达到节约内存的作用。
而生成器靠yield关键字实现,生成器的编写类似于函数,只不过将函数的return改成了yield:
生成器函数(generator function)和生成器(generator)
生成器函数是一种特殊的函数;生成器则是特殊的迭代器。
如果一个函数包含 yield 表达式,那么它是一个生成器函数
调用它会返回一个特殊的迭代器,称为生成器。
def func():
return 1
def gen():
yield 1
print(type(func)) # <class 'function'>
print(type(gen)) # <class 'function'>
print(type(func())) # <class 'int'>
print(type(gen())) # <class 'generator'>
生成器 gen 看起来和普通的函数没有太大区别。仅只是将 return 换成了 yield。
用 type() 函数打印二者的类型也能发现,func 和 gen 都是函数。
二者的返回值的类型就不同了。
func() 是一个 int 类型的对象;而 gen() 则是一个迭代器对象。
与普通函数的区别
生成器函数被调用后,其函数体内的代码并不会立即执行,
而是返回一个生成器(generator-iterator)。
当返回的生成器调用成员方法时,相应的生成器函数中的代码才会执行
网友评论