切片
取一个list或者一个tuple的元素是很常见的。在Python中,提供了切片(slice)操作符,可以大大简化操作。
L[0:3],表示从索引0开始取,取到索引为3,但不包括3,取出三个元素。另外如果第一个是0,还可以省略,写成L[:3]。
扩展:
tuple也是一种list,唯一不同是不可变。所以也可以进行切片,只是操作对象仍是tuple。
字符串‘XXX’,也可以看成list,每个元素就是一个字符。因此也可以进行切片,操作的结果仍然是字符串。
在很多编程语言中,针对字符串提供了很多截取函数,起目的就是对字符串切片。
迭代
如果给定一个list或者tuple,可以通过for循环来遍历这个list或tuple,这种遍历成为迭代(lteration)。
在Python中,迭代是通过for…in来完成的,而很多语言比如C语言,迭代list是通过下标完成的。list这种数据类型虽然有下标,但是其他可迭代对象,没有下标也可以进行迭代。比如dict就可以迭代。
默认下dict迭代的是key。如果要迭代value,可以用for value in d.values(),如果要同时迭代key和value,可以用for k,v in d.items()。
由于字符串也是可迭代对象,因此,也可以作用于for循环。
所以,当我们使用for循环时,只要作用一个可迭代对象,for循环就可以正常运行。
可以通过collections模块的lterable类型来判断。
另外,如果一定要实现下标循环,Python内置enumerate()函数可以把list变成索引-元素对,这样就可以在for循环中同时迭代索引和元素本身。
for循环里,同时引用两个变量,在Python中是很常见的。
列表生成式
列表生成式(List Comprehensions),是Python内置的非常简单强大的可以用来创建list的生成式。
比如要生成一个list[1,2,3,4,5,6,7,8,9,10],可以用list(range(1,11)):
但如果要生成[1*1,2*2,3*3……,10*10],可以通过循环。
也可以通过list生成式,
还可以在后面加if条件语句,这样可以进行筛选,
还可以使用两层循环,生成全排列,
利用list生成式可以写出非常简洁的代码。例如,列出当前目录下的所有文件和目录名,可以通过一行代码实现:
for循环可以同时使用两个甚至更多变量,因此列表生成式也可以使用两个变量来生成list,
注:如果list中既包含字符串,又包含整数,由于非字符串类型没有lower()方法,所以列表生成式会报错。使用内置函数isinstance函数可以判断。
生成器
在Python中,一边循环一边计算的机制,成为生成器:generator。
创建一个generator,第一种,只要把列表生成式的[]改成(),就可以了。
与list不同,g是一个generator。我们可以直接打印出list的每一个元素,但是我们要打印出generator时,可以通过next()函数,获得generator的下一个返回值。
generator保存的是算法,每次调用next()函数,就计算出g下一个元素的值,直到计算最后一个元素,没有更多的时候,就会抛出StopIteration的错误。
因为generator也是迭代对象,所以可以使用for循环实现迭代。
如果推算的算法比较复杂,用类似列表生成式的for循环无法实现时,还可以用函数实现。
比如斐波拉契数列用列表生成式写不出来是,但是通过函数可以。
※注:
a , b = b , a+b
理解为:
t = (b,a+b) #t是一个tuple
a = t[0]
b = t[1]
不用写出临时变量t就可以实现。
fib函数实际上是定义了斐波拉契数列的推算规律,可以从第一个元素开始,推算出后续任意元素,这种逻辑很类似generator。我们需要把print(b),改成yield b就可以实现了。
实际上generator和函数的执行流程不一样。函数是顺序执行,遇到return语句或者最后一行函数语句就返回;而generator的函数,在每次调用next()函数,遇到yield函数就返回,再次执行时从上次返回的yield处继续执行。
我们再看fib的例子,我们在循环过程中不断调用yield,就会不断中断。当然需要设置一个条件来跳出循环,不然就会产生一个无限的数列出来。
同样的,我们把函数改成generator,也基本不会用next()来获取下一个返回值,而是直接使用for循环来迭代
但是在调用generator的时候,发现拿不到他的return语句的返回值。如果想拿到返回值,必须捕获StopIteration错误,返回值包含在StopIteration的value中。
迭代器
可以直接作用for:
一类是集合数据类型,如list、tuple、dict、set、str等;
一类是generator,包括生成器和带yield的generator function。
这些可以直接作用与for循环的统称为可迭代对象:Iterable。
我们可以用isinstance()函数进行判断是否为Iterable。
同样,可以被next()函数调用,并且不断返回下一个值的对象叫做迭代器:Iterator。
我们也可以用isinstance()函数进行判断。
为什么list、dict、str等数据类型不是Iterator?
这是因为Python的Iterator对象表示的是一个数据流,Iterator对象可以被next()函数调用,并不断返回下一个数据,直到没有数据时抛出StopIteration错误。
可以把这个数据流看做是一个有序序列,但我们却不能提前知道序列的长度,只能不断通过next()函数实现按需计算下一个数据,所以Iterator的计算是惰性的,只有在需要返回下一个数据时它才会计算。
Iterator甚至可以表示一个无限大的数据流,例如全体自然数。而使用list是永远不可能存储全体自然数的。