python:容器、迭代器、生成器 简单介绍

python提供了多种数据类型来存放数据项。

之前已经介绍了几个python中常用的容器,分别是列表list、元组tuple、字典dict和集合set。

这几种数据结构在Python中是非常重要的部分,尤其是各自的特性部分。掌握好了,处理数据的时候会很方便。

容器 container

容器是一种把多个元素组织在一起的数据结构。容器中的元素可以通过for循环逐个地迭代获取,也可以通过in关键字来判断元素是否在容器中。

在Python中,常见的容器对象:

list、dequeue...

set、frozenset...

dict、defaultdict、OrderDict...

tuple、namedtuple...

str

file

引用一张之前从其他博文上截的图,觉得很形象,很好的解释了之间的关系。不过不好意思,出处找不到了


大部分容器都提供了某种方式可以获取到其中的每一个元素,但是这并不是容器本身提供的功能,而是可迭代对象赋予了容器这种能力。

迭代 iteration

什么叫迭代?

如果给定一个list或者tuple数据类型变量,我们可以通过for循环来遍历这个list或者tuple,那这种遍历可以成为迭代。

在java中,迭代list是通过下标index来完成的,例如:

for (i=0;i

val = param[index];

}

# 恰好最近在重新捡起java

在Python中,迭代是通过for...in 循环完成的。Python中的for循环可以用在string、list、tuple、dict等其他可迭代对象上。例如:

>>> d = {'a':1,'b':2,'c':3}

>>> for key in d: # dict

... print(key)

...

a

b

c

>>> for ch in 'AB': # str

... print(ch)

...

A

B

所以,当我们使用for循环时,我们不太去关心作用的对象究竟是list、tuple还是其他数据类型,只要作用于一个可迭代对象上,for循环就可以正常运行。

so...

可迭代对象 iterable

可迭代对象,Iterable。可直接使用for循环的对象统称为可迭代对象。

那么你可能会问,如何去判断一个对象是否是可迭代对象呢?

ans:方法是通过引入collections模块中的Iterable类型来判断,同时使用isinstance()。

>>> from collections import Iterable # 引入Iterable

>>> isinstance('abc',Iterable)

True

>>> isinstance(123,Iterable)

False

补充一小点知识,如何通过for循环,把list的索引和值都读出来呢?使用enumerate() 来完成。

Python内置的enumerate()枚举函数可以把一个list编程索引-元素对,这样就可以在for循环中同时迭代索引和元素本身。如下:

>>> l=['a','b','c','d']

>>> for ind,val in enumerate(l):

... print("%d %s"%(ind,val))

...

0 a

1 b

2 c

3 d

迭代器 iterator

可以被next()函数调用并不断返回下一个值的对象为迭代器,iterator。

Python中的iterator对象是一个带状态的对象,表示的是一个数据流,他实现了如下两个方法:

__iter__:返回迭代器本身;

__next__:返回容器的下一个元素;

虽然list、dict、tuple是可以迭代的对象,但不是迭代器。

但是可迭代对象实现了__iter__方法,该方法返回一个迭代器对象。

如何创建迭代器

iter()

如何创建一个可迭代对象?通过调用iter()方法实现,如下图所示:


next()

可迭代对象可以被next()调用并不断返回下一个数据,直到没有数据时抛出StopIteration错误。如下:


我们可以想象迭代器数据流看做是一个有序的序列,但是不能提前知道序列到底有多长,只能不断通过next()函数来实现读取下一个数据。

所以Iterator的计算是一个惰性的,至于在需要返回下一个数据时,他才会计算。

Iterator甚至可以表示一个无限大的数据流,例如全体自然数。而使用list是永远不可能存储全体自然数的。

生成器 generator

生成器是一种特殊的迭代器。

一个函数只返回一次,但一个生成器能暂停执行并返回一个中间的结果,当生成器的next()方法被调用时,它就又会从离开的地方继续运行,实现一边循环一边计算的机制,这种就称为生成器generator。

生成器创建方法

生产器的创建方法有两种:一是生成器表达式;二是yield关键字。

生成器表达式

直接上例子啦:注意一点就是,生成器最外层的是“()”,list最外成是“[]”。

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

>>> g

at 0x010B3690>

# 使用next()来获得generator的下一个返回值

>>> next(g)

0

>>> next(g)

1

# g保存的是算法,每次调用next(g),就计算出下一个元素的值,直到没有更多元素时抛错

yield关键字

如果一个函数定义中包含yield关键字,那么这个函数就不再是一个普通的函数,而是一个generator。

例如,用函数实现斐波那契数列,我们可以使用如下方法:

def fib(max):

n,a,b = 0,0,1

while n < max:

print(b)

a,b=b,a+b

n = n + 1

return 'done'

其中,fib()定义了斐波那契的推算规则。

那我们可以把fib()变成generator。如下:

def fib():

prev,curr = 0,1

while True:

yield curr

prev,curr = curr , curr + prev

上述函数体中,返回值不是return关键字了,而是yield,函数返回值是一个生成器对象。

当执行f=fib()时返回的是一个生成器对象,此时函数体中的代码不会执行,只有显示或隐式调用next()的时候才会真正执行里面的代码。

在每次调用next()的时候执行,遇到yield语句返回,再次执行时,从上次返回的yield语句处继续执行。

我们可以通过一个例子演示说明:

>>> def odd():

... print('step1')

... yield 1

... print('step2')

... yield 2

... print('step 3')

... yield 3

...

>>> o = odd()

>>> next(o)

step1

1

>>> next(o)

step2

2

好啦,今天就写到这~

❤ thanks for watching, keep on updating...