切片
切片就是切割list或者tuple里面的元素,获取某个或某段元素。
1 | L = ['a', 'b', 'c', 'd', 'e'] |
L[a:b] 表示返回从第a个元素到第b个元素,不包含第b个元素。 如果索引为0的话可以省略。
同样支持倒数切片,倒数第一个元素是的索引是-1
1 | L[-2:-1] |
切片操作不仅可以切割相邻的元素,还可以分段切割
1 | l = [1,2,3,4,5,6,7,8,9,10] |
L[a:b:c] 表示返回从第a个元素到第b个元素(不包含第b个元素),每c个元素取一个。
同样对tuple也支持,只是返回的结果格式还是tuple
对字符串也同样适用,返回的还是字符串
1 | str = '123456789' |
切片是一种很高能的操作。能随意截取list、tuple甚至字符串,相比于oc截取字符串的某一段,Python这种切片操作简单极了
迭代
用for循环来遍历一个可遍历对象称为迭代
可遍历对象: list、 tuple、 dict、 set、str…
迭代list
1 | l = [1, 2, 3] |
迭代tuple
1 | tup = (1,2,3) |
迭代dict
dict是key-value存储的,默认迭代的是key, 若想迭代value需要.values(), 若想同事迭代key-value 需要.items()。
dict的存储顺序是无序的,迭代结果的顺序并不一定按照顺序排列
1 | dict = {1:'a', 2:'b', 3:'c'} |
迭代set
1 | sets = set([1,2,3,4,4,2]) |
迭代str
1 | str = 'abc' |
带索引的list迭代
迭代一个list,还需要显示list的索引。在Java或oc中有for(int i = 0; i < list.count; i ++)这样的for循环,打印i就是list的索引。 在Python中有enumerate()函数,能拿到list的索引
1 | l = ['a','b','c'] |
多个迭代变量
迭代时两个变量,比如一个list里面放了tuple [(1,2),(3,4),(5,6)] 可以引入两个迭代变量,遍历内容。 注意点是tuple的元素个数必须固定,跟给定的迭代变量参数个数相同,否则会报错
1 | for a, b in [(1,2),(3,4),(5,6)] |
判断对象是否可迭代
引入collections模块的Iterable做类型判断
1 | from collections import Iterable |
列表生成式
List Comprehensions列表生成式,用简单的代码生成复杂的list
生成[1,2,3,4] 使用list(range(1,5)),x从1到5不包括5
1 | list(range(1,5)) |
普通列表生成式
如果要生成[1*1, 2*2, 3*3, 4*4, 5*5]的list的话怎么生成呢? 可以用for循环
1 | l = [] |
如果要用列表生成式的话,只需要一行代码就能搞定
1 | [x * x for x in range(1,5)] |
列表生成式[x * x for x in range(1,5)]可以这样理解:for循环是生成元素的,for循环生成的元素放到前面结果元素计算式x * x中计算得到最终结果,结果本身就在[]中,不需要append了。
带筛选条件的列表生成式
列表生成式还可以增加筛选条,比如,生成1-10(包括10)中所有偶数的平方组成的list
1 | [x * x for x in range(1,11) if x % 2 == 0] |
筛选条件跟在for循环后面,筛选for循环生成的元素,让只有符合条件的元素进入结果元素计算式中计算,组成最终的list
两层循环的列表生成式
需求:列出两个list里元素的两两一起的所有组合
1 | [n + m for n in ['a','b','c','d'] for m in ['A','B','C','D']] |
根据打印结果知道,其实就是循环嵌套。这是二层嵌套,其实也可以有n层嵌套,可以试试。下面是三次for循环,可以自己试试
1 | [n + m + x for n in ['a','b','c','d'] for m in ['A','B','C','D'] for x in '1234'] |
多个变量的列表生成式
嵌套循环其实就是多个变量的列表生成式,一层循环的多个变量同样适用。比如迭代(遍历)dict,同时迭代出key-value,然后组成list
1 | [str(k) + v for k,v in {1:'a', 2:'b', 3:'c', 4:'d'}.items()] #str()是类型转换,迭代出来的k是int类型,要想与字符串拼接要先转成str类型 |
生成器
介绍
列表生成式只能生成有一定规律的list,比如1-10的偶数平方list,1-100中能被3整除的list。每个元素都是能通过算法计算出来的。
当用到一个list时,为节省存储空间,不用创建出完整的list再去使用,可以在循环中不断推算出后面的元素。类似iOS中的UItableView,只创建显示到屏幕上的cell,在滑动过程中再去创建设置cell(其实是拿内存中闲置的cell,cell的循环机制)。这种边循环边计算的机制称为生成器(generator)
创建生成器1
创建一个generator方法很多,其中一种只要把生成式的[]换成()即可
1 | [x * x for x in range(1,10)] #列表生成式创建list |
遍历生成器元素
生成器是边循环边计算元素的,那怎么打印其中每个元素呢?有一个函数next()
1 | g = (x for x in range(3)) |
每次调用next(g)的时候,计算出下一个元素的值,当超出list的长度时,就会抛出异常StopIteration(停止迭代)
这种方法读取元素实在是太low了,generator也是可迭代对象,完全可以用for循环迭代
1 | g = (x for x in range(3)) |
创建生成器2
有一种数列跟生成器运行机制类似,就是斐波拉契数列,除了开始的两个1,每个数都是前两个数的和。这个数列就是边循环边计算出元素的。
可以用函数打印这样的一个数列,输出指定位数的斐波拉契数列
1 | def test(num): |
插曲:有趣的赋值方式
这里有一种很有趣的赋值方式,在oc和java中看不到。就是上面函数中的n, a, b = 0, 0, 1和a, b = b, a + b,这是一种同时赋值的方法,=右边的值赋值给=左边相应位置的参数,每个参数赋值是同时进行的,他们的值都是这条赋值式上面时获得的值。
比如a, b = b, a + b,在赋值的时候,a = b 和 b = a + b是同时进行的,最终的结果都是在a = 1, b = 2的前提下得到的。
1 | a = 1 |
在其他语言中,这种赋值要引入第三变量。不然第二条赋值结果会因为第一条赋值操作而改变。
上文中的test(num)函数变为生成器很简单,只需要把函数的print(b)换成yield b
1 | def test(num): |
如果一个函数定义中包含了关键字yield,那么这个函数不再是一个普通的函数,而是一个生成器
调用结果,返回的是一个generator对象:
1 | test(9) |
生成器的执行原理
在函数中添加了yield,这个函数就变成了生成器。这时就改变了Python函数的执行顺序,Python函数是顺序执行的,遇到return或最后一行语句就返回。如果变成了生成器,执行顺序就变成了遇到yield返回,下次执行会从上次返回yield的位置处继续执行
例如定义函数
1 | def test(): |
执行调用:
1 | test() |
和第一种创建的生成器一样,用for循环遍历该生成器 test()
1 | for n in test(): |
发现了一个问题,for循环遍历拿不到return的返回值END。看上面的next(a)调用,最后超出范围时抛出的错误: END, END在这里面。
其实生成器generator的return值在异常错误StopIteration的value值里
用循环遍历test(),并捕获异常,拿到return返回的END值
1 | a = test() |
总结:generator是在循环过程中不断计算出下一个元素的值,并在适当条件结束循环。对于函数改为的generator遇到return或者到函数的最后一行语句就是结束generator的指令。就是函数结束,generator结束
迭代器
可以直接作用于for循环的对象为可迭代对象: Iterable
可迭代对象有:list(数组)、tuple(元组)、dict(字典)、set(key的集合)、str(字符串)、generator(生成器/带yiel的函数)
引入collections模块里的Iterable 可以判断一个对象是否是Iterable(可迭代对象)
1 | from collections import Iterable |
可迭代对象里的generator,不但可以作用于for循环,还可以被next()不断调用并返回下一个值,直到抛出错误StopIteration。这种可以被next()函数调用不断返回下一个值得对象被称为迭代器Iterator
引入collections模块里的Iterator 可以判断一个对象是否是Iterator(迭代器)
1 | from collections import Iterator |
可迭代对象里的生成器generator是Iterator迭代器
其他的list(数组)、tuple(元组)、dict(字典)、set(key的集合)、str(字符串) 虽然是可迭代对象Iterable,但不是Iterator(迭代器)
可以用iter()函数把这些可迭代对象变为迭代器
1 | isinstance(iter({}), Iterator) |
为什么list这些可迭代对象不是迭代器呢?因为迭代器Iterator是一个数据流,可以存放无限大的数据,只是一个有序序列,不可能知道他的长度,只能不断next()计算下一个数据,只有在需要下一个数据的时候才去计算,是一种惰性计算。而list等这类可迭代对象都是可知长度的,不能next()循环计算下一个值。