列表生成式
常见的列表生成方式:
1.list
>>> list(range(1,5))
> [1,2,3,4]
2.for循环
l=[]
for i in range(1,5):
l.append(i)
>>>l
>[1,2,3,4]
3.列表生成式 : 在列表生成时加入限制判断条件
例:
#[1,2,3,4]
[x for x in range(1,5)]
可以添加限制条件
#[2.4]
[x for x in range(1,5) if x%2==0]
用于求全排列
#['AY','AZ','BY','BZ']
[a+b for a in 'AB' for b in 'YZ']
但是三层或三层以上的循环在实际中很少用到。
读取文件名
>>> import os
>>> [d for d in os.listdir('.')] # os.listdir可以列出文件和目录
['.emacs.d', '.ssh', '.Trash', 'Adlm', 'Applications', 'Desktop', 'Documents', 'Downloads', 'Library', 'Movies', 'Music', 'Pictures', 'Public', 'VirtualBox VMs', 'Workspace', 'XCode']
for循环其实可以同时使用两个甚至多个变量,比如dict的items()可以同时迭代key和value。
>>> d = {'x': 'A', 'y': 'B', 'z': 'C' }
>>> [k + '=' + v for k, v in d.items()]
['y=B', 'x=A', 'z=C']
生成器
“列表生成式”式生成器
创建生成器的其中一种方法,就是将列表生成式的 [ ] 换成 ( )
例:
>>> g = (x*x for x in range(1,5))
> g
> <generator object <genexpr> at 0x02AE8D48>
与列表生成式不同的是,这样创建出的生成器不会打印出g中每一个元素,而是如上所示。这是因为,生成器所保存的是一种算法,而不是某些具体的元素。
要打印出g中的每一个元素,需要使用next()方法:
>>> next(g)
> 1
>>> next(g)
> 4
>>> next(g)
> 9
>>> next(g)
> 16
>>> next(g)
>Traceback (most recent call last):
File "<stdin>", line 1, in <module>
StopIteration
当计算到最后一个元素后,没有更多的元素,计算机会抛出StopIteration错误
当然,也可以用for循环来直接输出,可以将g能生成的所有元素打印出来。但是不会有StopIteration
for i in g:
print(i)
函数式生成器 yield
斐波拉契数列用列表生成式写不出来,但是,用函数把它打印出来却很容易:
def fib(n):
x,a,b = 0,0,1
while x<n:
print(b)
a,b = b,a+b
x += 1
return 'done'
仔细观察,可以看出,fib函数实际上是定义了斐波拉契数列的推算规则,可以从第一个元素开始,推算出后续任意的元素,这种逻辑其实非常类似generator。
要把fib()函数变成generator,只需要将print(b)转换成yield b即可。
这就是定义generator的另一种方法。如果一个函数定义中包含yield关键字,那么这个函数就不再是一个普通函数,而是一个generator:
def fib(n):
x,a,b = 0,0,1
while x<n:
yield b
a,b = b,a+b
x += 1
return 'done'
generator和函数的执行流程不一样。函数是顺序执行,遇到return语句或者最后一行函数语句就返回。而变成generator的函数,在每次调用next()的时候执行,遇到yield语句返回,再次执行时从上次返回的yield语句处继续执行。
>>> for fib_num in fib(6):
... print(fib_num)
...
>1
>1
>2
>3
>5
>8
但是却提取不到return返回值 ‘done’。
前面说过,当计算到最后一个元素后,没有更多的元素,计算机会抛出StopIteration错误。
因此,如果想要拿到返回值,必须捕获StopIteration错误,返回值包含在StopIteration的value中。
>>> g = fib(6)
>>> while True:
... try:
... x = next(g)
... print('g:', x)
... except StopIteration as e:
... print('Generator return value:', e.value)
... break
...
g: 1
g: 1
g: 2
g: 3
g: 5
g: 8
Generator return value: done
迭代器
可以直接作用于for循环的对象统称为可迭代对象:Iterable
如:list,tuple,dict,set,str
还有上面提到的generator
可以使用isinstance()判断一个对象是否是Iterable对象.(from collections import Iterable)
而可迭代对象却不一定是迭代器(iterator)。可以被next()函数调用并不断返回下一个值的对象称为迭代器:Iterator。
符合这一条件的 : generator 不但可以作用于for循环,还可以被next()函数不断调用并返回下一个值,直到最后抛出StopIteration错误表示无法继续返回下一个值。
可以使用isinstance()判断一个对象是否是Iterator对象.(from collections import Iterator)
集合数据类型如list、dict、str等是Iterable但不是Iterator,不过可以通过iter()函数获得一个Iterator对象。