一、关系图

Python的数据结构容器(container)、可迭代对象(iterable)、迭代器(iterator)、生成器 (generator)、列表/集合/字典推导式(list,set,dict comprehension)之间的关系图

python容器的dockefile文件_迭代器

 二、容器

容器是一种把多个元素组织在一起的数据结构,容器中的元素可以逐个地迭代获取,可以用 in , not in 关键字判断元素是否包含在容器中。通常这类数据结构把所有的元素存储在内存中。Python的常见的容器对象有:list、set、dict、tuple、str 

尽管绝大多数容器都提供了某种方式来获取其中的每一个元素,但这并不是容器本身提供的能力,而是 可迭代对象 赋予了容器这种能力,当然并不是所有的容器都是可迭代的。 

三、可迭代对象(iterable)

如果给定一个list或tuple,我们可以通过for循环来遍历这个list或tuple,这种遍历我们称为迭代(Iteration)。

刚才说过,很多容器都是可迭代对象,此外还有更多的对象同样也是可迭代对象,比如处于打开状态的files,sockets等等。但凡是可以通过iter()方法返回一 个迭代器 的对象都可称之为可迭代对象。

 

四、迭代器(iterator)

那么什么迭代器呢?它是一个带状态的对象,他能在你调用 next() 方法的时候返回容器中的下一个值,任何实现了 __next__() 方法的对象都是迭代器,至于它是如何实现的这并不重要。

迭代器就像一个懒加载的工厂,等到有人需要的时候才给它生成值返回,没调用的时候就处于休眠状态等待下一次调用。 

五 for i in (iterable)的内部实现

在大多数情况下,我们不会一次次调用next方法去取值,而是通过 for i in (iterable)。

in后面的对象如果是一个迭代器,内部因为有iter方法才可以进行操作,所以,迭代器协议里面有iter和next两个方法,否则for语句无法应用。

python容器的dockefile文件_迭代器_02

 

 

 

python容器的dockefile文件_生成器_03

 

六、生成器(generator)

 生成器算得上是Python语言中最吸引人的特性之一,生成器其实是一种特殊的迭代器,不过这种迭代器更加优雅,它只需要一个 yiled 关键字。 

用生成器来实现斐波那契数列的例子是:

# 0, 1, 1, 2, 3, 5, 8, 13, 21, 34, ...
def fab(max_num):
    n, a, b = 0, 0, 1
    while n < max_num:
        yield b
        a, b = b, a + b
        n = n + 1


for i in fab(5):
    print(i)

 yield 的作用就是把一个函数变成一个 generator,带有 yield 的函数不再是一个普通函数,Python 解释器会将其视为一个 generator,如:fab(5) 。在 for 循环执行时,每次循环都会执行 fab 函数内部的代码,执行到 yield b 时,fab 函数就返回一个迭代值, 下次迭代时,代码从 yield b 的下一条语句继续执行,而函数的本地变量看起来和上次中断执行前是完全一样的,于是函数继续执行,直到再次遇到 yield。看起来就好像一个函数在正常执行的过程中被 yield 中断了数次,每次中断都会通过 yield 返回当前的迭代值。需要明确的就是生成器也是iterator迭代器,因为它遵循了迭代器协议。 

另一种获取生成器的方式:

gen = (x*2 for x in range(10))
print(type(gen))

########
<class 'generator'>

 

七、文件读取之生成器

如果直接对文件对象调用 read()或者readlines() 方法,会将整个文件读取到内存中,如果文件非常大,比如上百GB,会导致不可预测的内存占用。好的方法是利用固定长度的缓冲区来不断读取文件内容。通过 yield,我们不再需要编写读文件的迭代类,就可以轻松实现文件读取。

def read_file(fpath):
    block_size = 1024
    with open(fpath, 'rb') as f:
        while True:
            block = f.read(block_size)
            if block:
                yield block
            else:
                return

 逐行读取:for 循环中的文件句柄 f 就是一个可迭代对象,逐行将内容读取到内存中,内存中永远只保存一行的内容

with open("/hello/abc.txt", "r", encoding="utf-8") as f:
    for line in f:
        print(line, end="")

 实例:读取文件,找出文件中最长的行的长度:

max(len(x.strip()) for x in open('/hello/abc','r'))