为了使编写的python代码行数更少,更简单,有时候可以使用这些高级特性.
切片Slice 针对list
或tuple
取出里面特定范围的元素
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 L[0 :3 ] L[:3 ] L[-1 ] L[-2 :] L[-2 :-1 ] L[:10 :2 ] L[::5 ] (0 , 1 , 2 , 3 , 4 , 5 )[:3 ] L[:] L[::]
迭代Iteration 就是for
循环,不过python的迭代是只要是可迭代对象,不管有没有下标,都可以迭代.
除了list
和tuple
还有dict
包括字符串
都可以迭代
判断是否未可迭代对象 1 2 3 4 5 >>> form collections.abc import Iterable>>> isinstance ('abc' , Iterable)True >>> isinstance (123 , Iterable)False
同时迭代list的下标和元素 1 2 3 4 5 6 >>> for index, value in enumerate (['a' , 'b' , 'c' ]): ... print (index, value) 0 a1 b2 c
列表生成式 一行代码生成list
,或者可以理解为将一个用循环生成的列表用一行代码搞掂
1 2 3 4 5 6 7 8 9 10 11 12 13 14 >>> L = []>>> for x in range (1 , 11 ): ... L.append(x * x)>>> [x * x for x in range (1 , 11 )] [1 , 4 , 9 , 16 , 25 , 36 , 49 , 64 , 81 , 100 ]>>> [x * x for x in range (1 , 11 ) if x % 2 == 0 ] [4 , 16 , 36 , 64 , 100 ]>>> [m + n for m in 'ABC' for n in 'XYZ' ] ['AX' , 'AY' , 'AZ' , 'BX' , 'BY' , 'BZ' , 'CX' , 'CY' , 'CZ' ]
一些例子 1 2 3 4 5 6 7 8 9 10 11 12 >>> import os>>> [d for d in os.listdir(',' )] ['.emacs.d' , '.ssh' , '.Trash' , 'Adlm' , 'Applications' , 'Desktop' , 'Documents' , 'Downloads' , 'Library' , 'Movies' , 'Music' , 'Pictures' , 'Public' , 'VirtualBox VMs' , 'Workspace' , 'XCode' ]>>> d = {'x' : 'A' , 'y' : 'B' , 'z' : 'C' }>>> [k + '=' + v for k, v in d.items()] ['y=B' , 'x=A' , 'z=C' ]>>> L = ['Hello' , 'World' , 'IBM' , 'Apple' ]>>> [s.lower() for s in L] ['hello' , 'world' , 'ibm' , 'apple' ]
列表表达式与if…else 当if
在for
后面时,不能加else
因为for
后面要跟一个单一的
筛选条件,否则无法筛选
1 2 >>> [x for x in range (1 , 11 ) if x % 2 == 0 ] [2 , 4 , 6 , 8 , 10 ]
当if
在’for’前面时,一定要加else
因为for
前面是表达式,一定要有单一的
结果
1 2 >>> [x if x % 2 == 0 else -x for x in range (1 , 11 )] [-1 , 2 , -3 , 4 , -5 , 6 , -7 , 8 , -9 , 10 ]
生成器generator 如果要创建一个100万个元素的列表,肯定要占很大内存空间,如果我们每次访问都只是要某几个,那剩余的元素就是白白占用空间.
此时就需要生成器
,它可以一边循环一边计算生成元素.
生成器是一个对象 创建一个生成器,最简单就是把列表生成式的[]
改为()
1 2 3 4 5 6 >>> L = [x * x for x in range (10 )]>>> L [0 , 1 , 4 , 9 , 16 , 25 , 36 , 49 , 64 , 81 ]>>> g = (x * x for x in range (10 ))>>> g <generator object <genexpr> at 0x1022ef630 >
生成器保存的其实是算法
,它不保存元素,需要调用next()
函数生成下一个元素的值,知道最后一个,抛出StopIteration
错误
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 >>> next (g)0 >>> next (g)1 >>> next (g)4 >>> next (g)9 >>> next (g)16 >>> next (g)25 >>> next (g)36 >>> next (g)49 >>> next (g)64 >>> next (g)81 >>> next (g) Traceback (most recent call last): File "<stdin>" , line 1 , in <module> StopIteration
生成器是可迭代对象 一般不可能一次次使用next()
去迭代,而是用for
循环
1 2 3 4 5 6 7 8 9 10 11 12 13 14 >>> g = (x * x for x in range (10 ))>>> for n in g: print (n) 0 1 4 9 16 25 36 49 64 81
生成器函数 比如斐波拉契数列函数
1 2 3 4 5 6 7 def fib (max ): n, a, b = 0 , 0 , 1 while n < max : print (b) a, b = b, a + b n = n + 1 return 'done'
该函数实际上是定义了斐波拉契数列的算法,将其中的print(b)
改为yield b
它就会变成生成器函数
1 2 3 4 5 6 7 def fib (max ): n, a, b = 0 , 0 , 1 while n < max : yield b a, b = b, a + b n = n + 1 return 'done'
当一个函数存在yield
关键字,这个函数就会变成一个生成器函数,调用它返回一个生成器对象
1 2 3 >>> g = fib(6 )>>> g <generator object fib at 0x104feaaa0 >
生成器函数并不是遇到return
或最后一行
语句就返回,而是遇到yield
就返回,再次执行则从上次返回的yield
语句处继续执行.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 def odd (): print ('step 1' ) yield 1 print ('step 2' ) yield (3 ) print ('step 3' ) yield (5 )>>> o = odd()>>> next (0 ) step 1 1 >>> next (0 ) step 2 2 >>> next (0 ) step 3 3 >>> next (o) Traceback (most recent call last): File "<stdin>" , line 1 , in <module> StopIteration
调用生成器函数会得到一个生成器对象,多次调用相同的生成器函数会创建多个相互独立
的生成器对象
1 2 3 4 5 6 7 8 9 >>> next (odd()) step 1 1 >>> next (odd()) step 1 1 >>> next (odd()) step 1 1
实际上上面的代码是创建了3个相互独立
的生成器对象
生成器函数需要设退出循环的条件
,因为如果没有退出条件,我们不断调用,它就不断循环计算,就会产生一个无限数列出来
而生成器函数同样使用for
循环来迭代
1 2 for n in fib(6 ): print (n)
如果要拿到生成器函数的return
返回值,必须捕获StopIteration
,返回值在StopIteration
的value
中
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 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
循环的数据类型有:
集合数据类型: list
,tuple
,dict
,set
,str
等 生成器generator
: 生成器和带yield
的生成器函数 以上这些可以直接作用于for
循环的对象都是可迭代对象Iterable
其中生成器
不但可以作用于for
循环,还可以杯next()
不断调用并返回下一个值(直到抛出StopIteration
),这种对象被称为迭代器Iterator
总结下:
1 2 3 4 5 6 7 8 >>> from collections.abc import Iterable>>> isinstance ([], Iterable)True >>> from collections.abc import Iterator>>> isinstance ((x for x in range (10 )), Iterator)True
Iter()
函数可以把可迭代对象Iteratable
变成迭代器Iterator
1 2 3 4 >>> isinstance ([], Iterator)False >>> isinstance (iter ([]), Iterator)True
python的迭代器对象Iterator
表示的是一个数据流,Iterator
对象可以被next()
函数调用并不断返回下一个有效值,直到没有数据抛出StopIteration
错误.
可以把这个数据流看成一个有序序列,但我们却不能提前知道序列的长度.
Iterator
的计算是惰性的,只有在有需要返回下一个数据时它才会计算.
因此Iterator
甚至可以表示一个无限大的数据流,比如全体自然数.而list
,dict
,str
等这些就不可以,这也是为什么这些数据类型不是迭代器Iterator
的原因,因为它们是有限的.
for循环本质 python的for循环本质就是通过不断调用next()
函数实现的:
1 2 3 4 5 6 7 8 9 10 11 12 for x in [1 , 2 , 3 , 4 , 5 ]: pass it = iter ([1 , 2 , 3 , 4 , 5 ]) whild True : try : x = next (it) except StopIteration: break
迭代器小结 凡是可作用于for
循环的对象都是Iterable
类型;
凡是可作用于next()
函数的对象都是Iterator
类型,它们表示一个惰性计算的序列;
集合数据类型如list
、dict
、str
等是Iterable
但不是Iterator
,不过可以通过iter()
函数获得一个Iterator
对象。