python编一个真值表生成软件_Python 迭代器与生成器

本文详细介绍了Python中的迭代器、可迭代对象和生成器的概念,通过实例展示了如何使用迭代器实现斐波那契数列,并探讨了生成器在迭代过程中的优势和应用,包括生成器表达式和带有`yield`的生成器函数。最后,文章指出生成器在处理大型数据集和实现协程、异步IO等方面的重要作用。
摘要由CSDN通过智能技术生成

要完全理解透生成器,需要我们先掌握三个概念:可迭代对象(Iterable)

迭代器(Iterator)

迭代(Iteration)

放一张图来理解,来自这里额外提到了容器(container),说的是我们的集合类对象,如 list、set、dict,它们将多个元素组织在一起,这些对象就可以称为 container。

可迭代对象:

可直接作用于for循环的对象统称为Iterable 。具体的实现是,Python 中的对象只要定义了__iter__方法(该方法返回一个迭代器对象),或者定义了支持下标索引的__getitem__方法,那么这个对象就是可迭代对象。

>>> from collections import Iterable

>>> isinstance([], Iterable)

True

>>> isinstance({}, Iterable)

True

>>> isinstance([x for x in range(10)], Iterable)

True

迭代器:

可作用于next()函数的对象都是Iterator。具体的实现是,任何对象只要定义了__iter__和__next__方法,那就是迭代器对象;迭代器表示一个惰性计算的序列,需要__iter__返回迭代器自身,__next__返回迭代器中的下一个值,迭代到结尾时引发 StopIteration 异常;也就是说迭代器在遍历集合时,并不是将所有的元素事先都准备好,而是迭代到某个元素时才去计算该元素,利用这一特性我们可以去遍历一些巨大的集合,之前总结的函数式编程中,map,reduce,filter函数返回的就是一个新的迭代器。

还有一点需要明确的,迭代器都是可迭代对象,可迭代对象可以通过iter()返回一个新的迭代器。

>>> L = [1, 2, 3, 4, 5]

>>> '__iter__' in dir(L)

True

>>> '__next__' in dir(L)

False

>>> newL = iter(L)

>>> '__next__' in dir(newL)

True

>>> newL.__next__()

1

>>> newL.__next__()

2

# 定义斐波拉契数的迭代器

>>> class fib(object):

... def __init__(self):

... self.prev = 0

... self.curr = 1

... def __iter__(self):

... return self

... def __next__(self):

... value = self.curr

... self.curr += self.prev

... self.prev = value

... return value

...

>>> f = fib()

>>> for i in f:

... if i > 20: break

... print(i)

...

1

1

2

3

5

8

13

从上面的迭代操作中,可以看出 for 循环其实是调用__iter__获得迭代器,再调用__next__获取元素,迭代器内部状态保存在当前实例对象的prev以及cur属性中,在下一次调用中将使用这两个属性。每次调用next()方法都会执行以下两步操作:修改状态,以便下次调用next()方法

计算当前调用的结果

迭代器的使用非常普通,Python的内置库itertools就是专门返回迭代器对象的,这篇博文专门介绍itertools库的,我从中列举了一些:

# 累加

>>> import itertools

>>> a = itertools.accumulate(range(10))

>>> a

>>> print(list(a))

[0, 1, 3, 6, 10, 15, 21, 28, 36, 45]

# 连接列表或迭代器

>>> c = itertools.chain(range(3), range(4), [0, 1, 2, 3, 4])

>>> print(list(c))

[0, 1, 2, 0, 1, 2, 3, 0, 1, 2, 3, 4]

# 按照真值表筛选元素

>>> x = itertools.compress(range(5), (True, False, True, True, False))

>>> print(list(x))

[0, 2, 3]

# 计数器,可以指定起始位置和步长

>>> x = itertools.count(start=20, step=-1)

>>> print(list(itertools.islice(x, 0, 10, 1)))

[20, 19, 18, 17, 16, 15, 14, 13, 12, 11]

# 按照分组函数的值对元素进行分组

>>> x = itertools.groupby(range(10), lambda x: x < 5 or x > 8)

>>> for condition, numbers in x:

... print(condition, list(numbers))

True [0, 1, 2, 3, 4]

False [5, 6, 7, 8]

True [9]

# 类似map

>>> x = itertools.starmap(str.islower, 'aBCDefGhI')

>>> print(list(x))

[True, False, False, False, True, True, False, True, False]

生成器:

有了前面的铺垫,我们就能更好地理解生成器了。生成器是什么?说白了生成器就是一种特殊的迭代器,不过它的实现方式更为简单优雅,同样我们可以明确的是,任何生成器都是迭代器,生成器也是一个惰性计算的序列。

我们来看看生成器的两种定义方式:

1、生成器表达式:

>>> [i * i for i in range(5)]# 注意 Python3 中 range函数是迭代器

[0, 1, 4, 9, 16]

# 根据列表生成式,只需要简单修改就可以定义生成器

>>> (i * i for i in range(3))

at 0x7f59ed8fc3b8>

2、另一种定义复杂推导算法的生成器需要引入一个强大的关键字yield:

# 斐波那契序列的生成器函数

>>> def fib():

... prev = curr = 1

... yield prev #1

... yield curr #2

... while True:

... prev, curr = curr, prev + curr

... yield curr

...

>>> f = fib()

>>> f

>>> for i in f: # 还可以使用 next() 遍历生成器

... if i > 20: break

... print(i)

...

1

1

2

3

5

8

13

分析一下流程:调用生成器函数时只返回一个 generator 对象 f,函数并没有执行;

通过 for 循环生成器才开始执行,执行到 #1 yield prev 处,返回 yield 处的参数 prev,此时就打印出了1;

继续 for 循环,生成器函数将在上一次停止的语句处继续执行,遇到 #2 yield curr 返回,此时又打印出了1;

如此反复,直到i大于20跳出循环结束调用。

对比迭代器和生成器,实现同样的功能,生成器会显得更加优雅简洁。

迭代

一句话总结迭代:按照一定的顺序逐个访问容器中每一个元素的过程;也就是我们折腾斐波那契序列的过程限于篇幅,生成器就介绍到这里,但生成器的威力远不止此,下一篇将通过生成器和 yield 引出协程和异步IO等。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值