python列表生成式&生成器&迭代器
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了python列表生成式&生成器&迭代器相关的知识,希望对你有一定的参考价值。
一、列表生成式
什么是列表生成式?
列表生成式是快速生成列表的一种方式。(貌似有些废话)
更专业点的说法:列表生成式即List Comprehensions,是Python内置的非常简单却强大的可以用来创建list的生成式。
在python2.7里
举个例子,要生成list [1,2,3,4,5],可以用range(1,6)
>>> range(1,6) [1, 2, 3, 4, 5]
但是如果要生成[1x1,2x2,3x3,4x4,5x5]怎么做呢?
普通青年做法:
>>> L = [] >>> for x in range(1,6): ... L.append(x*x) ... >>> L [1, 4, 9, 16, 25]
但是这种方式,太繁琐、也太LOW,用列表生成式一行代码搞定:
>>> [ x*x for x in range(1,6) ] [1, 4, 9, 16, 25]
在python3里
>>> range(1,6)
range(1, 6)
>>> L = []
>>> for x in range(1,6):
... L.append(x*x)
...
>>> L
[1, 4, 9, 16, 25]
>>> [ x*x for x in range(1,6) ]
[1, 4, 9, 16, 25]
说明:
python2中的range返回的是一个列表
python3中的range返回的是一个迭代值
二、生成器
通过列表生成式,我们可以直接创建一个列表。但是,受到内存限制,列表容量肯定是有限的。而且,创建一个包含100万个元素的列表,不仅占用很大的存储空间,如果我们仅仅需要访问前面几个元素,那后面绝大多数元素占用的空间都白白浪费了。
所以,如果列表元素可以按照某种算法推算出来,那我们是否可以在循环的过程中不断推算出后续的元素呢?这样就不必创建完整的list,从而节省大量的空间。在Python中,这种一边循环一边计算的机制,称为生成器:generator。
如何创建生成器呢?
方法一:(把列表生成式的[]变为(),就创建了一个generator)
>>> L = [x * x for x in range(8)] >>> L [0, 1, 4, 9, 16, 25, 36, 49] >>> S = (x * x for x in range(8)) >>> S <generator object <genexpr> at 0xb7102fcc> >>>
如何打印generator的每一个元素呢?
方法一: >>> next(S) 0 >>> next(S) 1 >>> next(S) 4 >>> next(S) 9 >>> next(S) 16 >>> next(S) 25 >>> next(S) 36 >>> next(S) 49 >>> next(S) Traceback (most recent call last): File "<stdin>", line 1, in <module> StopIteration >>> # 使用next方法来获取下一回的返回值,最终找不到更多的元素时,会抛出StopIteration错误。 #更好的方式,推荐使用for循环来获取元素值 >>> S = (x * x for x in range(8)) >>> for n in S: ... print(n) ... 0 1 4 9 16 25 36 49 >>>
方法二:函数(推算的算法比较复杂,用类似列表生成式的for
循环无法实现的时候,还可以用函数来实现)
最著名的例子:斐波拉契数列(Fibonacci),除第一个和第二个数外,任意一个数都可由前两个数相加得到:
1, 1, 2, 3, 5, 8, 13, 21, 34, 55...
def fib(max): n,a,b = 0,0,1 while n < max: #print(b) yield b a,b = b,a+b n += 1 return "over" #一个函数定义中包含yield关键字,那么这个函数就不再是一个普通函数,而是一个generator >>> f = fib(6) >>> f <generator object fib at 0x104feaaa0>
最难理解的就是generator和函数的执行流程不一样。函数是顺序执行,遇到return语句或者最后一行函数语句就返回。
而变成generator的函数,在每次调用next()的时候执行,遇到yield语句返回,再次执行时从上次返回的yield语句处继续执行。
# next方法获取值 >>>data = fib(10) >>>print(data) >>>print(data.__next__()) #更好的方式 >>> for n in fib(6): ... print(n) ... 1 1 2 3 5 8 # return 值只有在发生StopIteration错误时,才返回 >>> list = fib(6) >>> while True: ... try: ... x = next(list) ... print(‘list:‘, x) ... except StopIteration as e: ... print(‘return value:‘, e.value) ... break ... list: 1 list: 1 list: 2 list: 3 list: 5 list: 8 return value: over
扩展:
yield实现在单线程的情况下实现并发运算的效果
import time def consumer(name): print("%s 准备吃包子啦!" % name) while True: baozi = yield print("包子[%s]来了,被[%s]吃了" % (baozi,name)) #c = consumer("R") #c.__next__() #c.__next__() def producer(name): c = consumer(‘A‘) c2 = consumer("B") c.__next__() c2.__next__() print("老子开始准备做包子了") for i in range(10): time.sleep(1) print("做了2个包子") c.send(i) c2.send(i) producer("coco")
三、迭代器
可迭代对象:可作用于for循环的对象都是可迭代对象(Iterable)
迭代器:可以被next()函数调用并不断返回下一个值的对象称为迭代器(Iterator),它们表示一个惰性计算的序列
判断是否是可迭代类型:
# 可迭代类型:list、tuple、dict、set、str、generator >>> from collections import Iterable >>> isinstance([],Iterable) True >>> isinstance([1,2,3],Iterable) True >>> isinstance({},Iterable) True >>> isinstance((),Iterable) True >>> isinstance((4,5,6),Iterable) True >>> isinstance({},Iterable) True >>> isinstance(‘coco‘,Iterable) True >>> isinstance((x*x for x in range(1,6)),Iterable) True >>> isinstance(200,Iterable) False >>>
判断是否是迭代器:
# 生成器都是Iterator对象,但list、dict、str虽然是Iterable,却不是Iterator >>> from collections import Iterator >>> isinstance((x for x in range(10)), Iterator) True >>> isinstance([1,2], Iterator) False >>> isinstance({}, Iterator) False >>> isinstance(‘test‘, Iterator) False # 但是可以把list、dict、str等Iterable变成Iterator可以使用iter()函数: >>> isinstance(iter([1,2]), Iterator) True >>> isinstance(iter(‘test‘), Iterator) True
说明:
python的for循环本质上就是通过不断调用next()函数来实现的。
# for循环 for x in [1, 3, 5,7]: pass # 使用next循环获取值的等价写法 it = iter([1, 3, 5,7]) while True: try: # 获得下一个值: x = next(it) except StopIteration: # 遇到StopIteration就退出循环 break
以上是关于python列表生成式&生成器&迭代器的主要内容,如果未能解决你的问题,请参考以下文章