切片(Slice)
具体形式:L[0:3],其中L为list名称,0:3代表list的取值范围,与matlab中的数组取值类似。list、tuple、字符串可以用切片操作。
list切片
下面以一个list为例来说明切片的用法:
1 | L=['Michael', 'Sarah', 'Tracy', 'Bob', 'Jack'] |
tuple切片
由于tuple也是一种list,因此tuple也可以用切片操作,其操作结果仍是tuple:
1 | L=(0,1,2,3,4) |
字符串切片
字符串也可以看成是一种list,因此,字符串也可以进行切片操作。
1 | L='ZHANGSAN' |
练习题
利用切片操作,实现一个trim()函数,去除字符串首尾的空格,注意不要调用str的strip()方法。
代码如下:
1 | # -*- coding: utf-8 -*- |
迭代
通过for循环来遍历list或tuple称为迭代。只要是可迭代对象,无论有无下标,都可以迭代。
迭代dict
默认情况下,dict迭代的是key。如果要迭代value,可以用for value in d.values()语句,如果要同时迭代key和value,可以用for k,v in d.items()语句。由于dict的存储不是按照list的方式顺序排列,因此迭代出的结果顺序很可能不一样。
1 | d={'a':1,'b':2,'c':3} |
迭代字符串
字符串也是可迭代对象,也可以作用于for循环。
1 | d='abc' |
对list实现下标循环
通过enumerate函数把list变成索引-元素对,便可以在for循环中同时迭代索引和元素本身:
1 | for i,value in enumerate(['A','B','C']): |
练习题
请使用迭代查找一个list中最小和最大值,并返回一个tuple。
代码如下:
1 | # -*- coding: utf-8 -*- |
列表生成式
使用列表生成式,可以通过一个list快速生成另一个list。
如要生成list[1,2,3,4,5,6,7,8,9]可用list(range(1,10))生成。
若要生成[1x2,2x2,3x3,...,10x10]可用[x*x for x in range(1,11)]生成。
写列表生成式时,要把生成的元素放到前面,后面再跟for循环,for循环后可以加上if判断,也可以使用两层循环:
1 | L=[x*x for x in range(1,11) if x%2==0] |
for循环可以同时使用两个或多个变量,如dict的items可以同时迭代key和value:
1 | d={'x':1,'y':2,'z':3} |
因此列表生成式也可以使用两个变量来生产list:
1 | d={'x':'1','y':'2','z':'3'} |
注意:这里的value只能为str类型,由于非字符串类型没有lower()方法,所以列表生成式会报错。可以使用isinstance函数来判断一个变量a是不是字符串,具体形式为isinstance(a,str)。
if…else
在使用列表生成式时,不能在最后的if加上else。这是因为跟在for后面的if是一个筛选条件,不能带else。而把if写在for前面必须加else,否则会报错。这是因为for前面的部分是一个表达式,其必须要计算出一个结果。
练习题
请修改列表生成式,通过添加if语句保证列表生成式能正确地执行。
代码如下:
1 | # -*- coding: utf-8 -*- |
生成器
在循环过程中不断推算出后续元素,故不必创建完整list,从而节省大量空间的机制,称为生成器(generator)。
创建生成器:将列表生成式的[]改成()
1 | L=[x*x for x in range(10)] |
打印生成器的元素
方法一:
通过next()函数单个打印生成器中的元素,具体形式如下:next(g)
方法二:
使用for循环打印,具体形式如下:
1 | g = (x * x for x in range (10)) |
如果生成器推算的算法比较复杂,用类型列表生成式的for循环无法实现时,还可以用函数来实现。比如打印斐波拉契数列:
1 | def fib(max): |
如果一个函数定义中包含yield关键字,那么这个函数就不再是一个普通函数,而是一个generator函数,调用一个generator函数将返回一个generator。变成generator的函数在每次调用next()的时候执行,遇到yield语句返回,再次执行时从上次返回的yield语句处继续执行。
例如,定义一个generator函数,依次返回数字1,3,5:
1 | def odd(): |
而每次调用next(odd())时,每次都会返回1.这是由于odd()会创建一个新的generator对象,每次调用next(odd())就创建一个完全独立的generator。
在斐波那契数列的例子中,在循环里不断调用yield,就会不断中断程序,此时需要给循环设置一个条件来退出循环,不然就会产生一个无限的数列,
把函数改成generator函数后,基本上不会用next()来获取下一个返回值,而是直接用for循环来迭代:
1 | def fib(max): |
用for循环调用generator时,是拿不到generator的return语句的返回值,若想要拿到返回值,必须捕获StopIteration错误,返回值包含在StopIteration的value中:
1 | def fib(max): |
练习题
杨辉三角定义如下:
1 | 1 |
把每一行看做一个list,试写一个generator,不断输出下一行的list。
代码如下:
1 | # -*- coding: utf-8 -*- |
迭代器
可以直接作用于for循环的对象统称为可迭代对象Iterable。
判断一个对象是可迭代对象
可通过collections.abc模块的Iterable类型判断。
1 | from collections.abc import Iterable |
可以被next()函数调用并不断返回下一个值的对象称为迭代器:Iterator。
生成器都是Iterator对象,但list、dict、str虽然是Iterable,却不是Iterator。这是因为Iterator的对象表示的是一个
数据流,可以把这个数据流看作是一个未知长度的有序序列,Iterator甚至可以表示一个无限大的数据流,例如全体自然数。
把list、dict、str从Iterable变成Iterator
可以使用iter()函数把list、dict、str从Iterable变成Iterator,其表现形式为:isinstance(iter([]),Iterator),其中,[]可替换为dict、str的形式。
小结
可作用于for循环的对象都是Iterable类型。
可作用于next()函数的对象都是Iterator类型,它们表示一个惰性计算的序列。
list、dict、str虽然是Iterable,却不是Iterator。但可以使用iter()函数把list、dict、str从Iterable变成Iterator