1.切片:取一个list或tuple的部分元素是非常常见的操作,比如说取list中的前n个元素,我们用循环来实现这样的操作:
>>> L = ['Michael','Sarah','Tracy','Bob','Jack']
对这种经常取指定索引范围的操作,用循环十分繁琐,因此,Python提供了切片(Slice)操作符,能大大简化这种操作。
>>>L[0:3]
['Michael', 'Sarah', 'Tracy']
切片取的是索引0,1,2的元素。更简洁的是如果索引是从0开始,那么我们直接写成 L[:3] 同样的取中间某个元素 L[1:2], 倒着取也可 L[-2,-1],。
这样举个例子:
>>> L = list(range(100))
>>> L
[0,1,2,3, ...,99]
这样切片的时候,有L[:10], L[-10:], L[:10:2]……
tuple的切片仍然是tuple。字符串'xxx'也可以看成是一种list,每个元素就是一个字符。因此,字符串也可以用切片操作,只是操作结果仍是字符串。
2.迭代:如果给定一个list或tuple,我们可以通过for循环来遍历这个list或tuple,这种遍历我们称为迭代(Iteration)。Python的循环是用for……in的方式来完成,而且Python的for循环不仅可以用在list或tuple上,还可以作用在其他可迭代(Iterable)对象上,eg:dict.
可以看到从dict里迭代不像list索引,顺序不确定。
默认情况下,dict迭代的是key。如果要迭代value,可以用for value in d.values(),如果要同时迭代key和value,可以用for k, v in d.items()。
由于字符串也是可迭代对象,因此,也可以作用于for循环: for ch in 'ABC'
只要是可迭代对象我们就可以用for循环,那么,如何判断一个对象是可迭代对象呢?方法是通过collections模块的Iterable类型判断:
如果想跟java一样的下标循环,我们用enumerate()函数把list变成索引-元素对,这样就可以在for循环中同时迭代索引和元素本身:
上面的for循环里,同时引用了两个变量,在Python里是很常见的,比如下面的代码:
>>> for x, y in [(1,1), (2,4), (3,9)]
:...print(x, y)
1 1
2 4
3 9
3.列表生成式:列表生成式即List Comprehensions,是Python内置的非常简单却强大的可以用来创建list的生成式。要生成一个list[1,2,3,4,5],我们用list(range(1,6))。但如果要生成[1x1, 2x2, 3x3, ..., 10x10]怎么做?
方法一:循环
方法二:列表生成式:>>> [x * x for x in range(1,11)]
[1,4,9,16,25,36,49,64,81,100]
并且for循环后面还可以加上if判断,这样我们就可以筛选出仅偶数的平方:
>>> [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']
运用列表生成式,可以写出非常简洁的代码。例如,列出当前目录下的所有文件和目录名,可以通过一行代码实现:
因此,列表生成式也可以使用两个变量来生成list:
最后把一个list中所有的字符串变成小写:
4.生成器:通过列表生成式,我们可以直接创建一个列表。但是,受到内存限制,列表容量肯定是有限的。而且,创建一个包含100万个元素的列表,不仅占用很大的存储空间,如果我们仅仅需要访问前面几个元素,那后面绝大多数元素占用的空间都白白浪费了。所以,如果列表元素可以按照某种算法推算出来,那我们是否可以在循环的过程中不断推算出后续的元素呢?这样就不必创建完整的list,从而节省大量的空间。在Python中,这种一边循环一边计算的机制,称为生成器:generator。
创建一个generator的方法有:把[ ]换成( )
查看g中每一个元素,用next()方法一个个查看,到最后一个抛出StopIteration的错误。当然更好的方法是用for循环,因为generator也是一个可迭代对象。
定义generator的另一种方法。如果一个函数定义中包含yield关键字,那么这个函数就不再是一个普通函数,而是一个generator:最难理解的就是generator和函数的执行流程不一样。函数是顺序执行,遇到return语句或者最后一行函数语句就返回。而变成generator的函数,在每次调用next()的时候执行,遇到yield语句返回,再次执行时从上次返回的yield语句处继续执行。举个例子:
调用该generator时,首先要生成一个generator对象,然后用next()函数不断获得下一个返回值
odd不是普通函数,而是generator,在执行过程中,遇到yield就中断,下次又继续执行。执行3次yield后,已经没有yield可以执行了,所以,第4次调用next(o)就报错。但是用for循环调用generator时,发现拿不到generator的return语句的返回值。如果想要拿到返回值,必须捕获StopIteration错误,返回值包含在StopIteration的value中。
这里再贴上练习题答案:
def triangles():
L=[1]
yield L
while True:
L=[1]+[L[x]+L[x+1] for x in range(len(L)-1)]+[1]
yield L
生成器小结:
generator是非常强大的工具,在Python中,可以简单地把列表生成式改成generator,也可以通过函数实现复杂逻辑的generator。
要理解generator的工作原理,它是在for循环的过程中不断计算出下一个元素,并在适当的条件结束for循环。对于函数改成的generator来说,遇到return语句或者执行到函数体最后一行语句,就是结束generator的指令,for循环随之结束。
请注意区分普通函数和generator函数,普通函数调用直接返回结果。
generator函数的“调用”实际返回一个generator对象。
5.迭代器:我们已经知道,可以直接作用于for循环的数据类型有以下几种:
一类是集合数据类型,如list、tuple、dict、set、str等;
一类是generator,包括生成器和带yield的generator function。
这些可以直接作用于for循环的对象统称为可迭代对象:Iterable。可以使用isinstance()判断一个对象是否是Iterable对象:
而生成器不但可以作用于for循环,还可以被next()函数不断调用并返回下一个值,直到最后抛出StopIteration错误表示无法继续返回下一个值了。
可以被next()函数调用并不断返回下一个值的对象称为迭代器:Iterator。同时可以使用isinstance()判断一个对象是否是Iterator对象:
生成器都是Iterator对象,但list、dict、str虽然是Iterable,却不是Iterator。把list、dict、str等Iterable变成Iterator可以使用iter()函数:
你可能会问,为什么list、dict、str等数据类型不是Iterator?
这是因为Python的Iterator对象表示的是一个数据流,Iterator对象可以被next()函数调用并不断返回下一个数据,直到没有数据时抛出StopIteration错误。可以把这个数据流看做是一个有序序列,但我们却不能提前知道序列的长度,只能不断通过next()函数实现按需计算下一个数据,所以Iterator的计算是惰性的,只有在需要返回下一个数据时它才会计算。
Iterator甚至可以表示一个无限大的数据流,例如全体自然数。而使用list是永远不可能存储全体自然数的。
迭代器小结:
凡是可作用于for循环的对象都是Iterable类型;
凡是可作用于next()函数的对象都是Iterator类型,它们表示一个惰性计算的序列;
集合数据类型如list、dict、str等是Iterable但不是Iterator,不过可以通过iter()函数获得一个Iterator对象。Python的for循环本质上就是通过不断调用next()函数实现的。
生成器那节杨辉三角突然断电了,以前还用过c和java做过这道题,唉,真是僵硬~~~百度了才知道怎么写。加油吧少年,时间不多了。