切片
切片就是切割list或者tuple里面的元素,获取某个或某段元素。
1 | 'a', 'b', 'c', 'd', 'e'] L = [ |
L[a:b]
表示返回从第a
个元素到第b
个元素,不包含第b
个元素。 如果索引为0
的话可以省略。
同样支持倒数切片,倒数第一个元素是的索引是-1
1 | -2:-1] L[ |
切片操作不仅可以切割相邻的元素,还可以分段切割
1 | 1,2,3,4,5,6,7,8,9,10] l = [ |
L[a:b:c]
表示返回从第a
个元素到第b
个元素(不包含第b
个元素),每c
个元素取一个。
同样对tuple也支持,只是返回的结果格式还是tuple
对字符串也同样适用,返回的还是字符串
1 | '123456789' str = |
切片是一种很高能的操作。能随意截取list、tuple甚至字符串,相比于oc截取字符串的某一段,Python这种切片操作简单极了
迭代
用for
循环来遍历一个可遍历对象称为迭代
可遍历对象: list、 tuple、 dict、 set、str…
迭代list
1 | 1, 2, 3] l = [ |
迭代tuple
1 | 1,2,3) tup = ( |
迭代dict
dict是key-value存储的,默认迭代的是key, 若想迭代value需要.values()
, 若想同事迭代key-value 需要.items()
。
dict的存储顺序是无序的,迭代结果的顺序并不一定按照顺序排列
1 | 1:'a', 2:'b', 3:'c'} dict = { |
迭代set
1 | 1,2,3,4,4,2]) sets = set([ |
迭代str
1 | 'abc' str = |
带索引的list迭代
迭代一个list,还需要显示list的索引。在Java或oc中有for(int i = 0; i < list.count; i ++)
这样的for循环,打印i就是list的索引。 在Python中有enumerate()
函数,能拿到list的索引
1 | 'a','b','c'] l = [ |
多个迭代变量
迭代时两个变量,比如一个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 | 1,5)) list(range( |
普通列表生成式
如果要生成[1*1, 2*2, 3*3, 4*4, 5*5]
的list的话怎么生成呢? 可以用for循环
1 | l = [] |
如果要用列表生成式的话,只需要一行代码就能搞定
1 | for x in range(1,5)] [x * x |
列表生成式[x * x for x in range(1,5)]
可以这样理解:for
循环是生成元素的,for
循环生成的元素放到前面结果元素计算式x * x
中计算得到最终结果,结果本身就在[]
中,不需要append
了。
带筛选条件的列表生成式
列表生成式还可以增加筛选条,比如,生成1-10(包括10)中所有偶数的平方组成的list
1 | for x in range(1,11) if x % 2 == 0] [x * x |
筛选条件跟在for循环后面,筛选for循环生成的元素,让只有符合条件的元素进入结果元素计算式
中计算,组成最终的list
两层循环的列表生成式
需求:列出两个list里元素的两两一起的所有组合
1 | for n in ['a','b','c','d'] for m in ['A','B','C','D']] [n + m |
根据打印结果知道,其实就是循环嵌套。这是二层嵌套,其实也可以有n层嵌套,可以试试。下面是三次for循环,可以自己试试
1 | for n in ['a','b','c','d'] for m in ['A','B','C','D'] for x in '1234'] [n + m + x |
多个变量的列表生成式
嵌套循环其实就是多个变量的列表生成式,一层循环的多个变量同样适用。比如迭代(遍历)dict,同时迭代出key-value,然后组成list
1 | for k,v in {1:'a', 2:'b', 3:'c', 4:'d'}.items()] #str()是类型转换,迭代出来的k是int类型,要想与字符串拼接要先转成str类型 [str(k) + v |
生成器
介绍
列表生成式只能生成有一定规律的list,比如1-10的偶数平方list,1-100中能被3整除的list。每个元素都是能通过算法计算出来的。
当用到一个list时,为节省存储空间,不用创建出完整的list再去使用,可以在循环中不断推算出后面的元素。类似iOS中的UItableView,只创建显示到屏幕上的cell,在滑动过程中再去创建设置cell(其实是拿内存中闲置的cell,cell的循环机制)。这种边循环边计算的机制称为生成器(generator)
创建生成器1
创建一个generator
方法很多,其中一种只要把生成式的[]
换成()
即可
1 | for x in range(1,10)] #列表生成式创建list [x * x |
遍历生成器元素
生成器是边循环边计算元素的,那怎么打印其中每个元素呢?有一个函数next()
1 | for x in range(3)) g = (x |
每次调用next(g)
的时候,计算出下一个元素的值,当超出list的长度时,就会抛出异常StopIteration(停止迭代)
这种方法读取元素实在是太low了,generator也是可迭代对象,完全可以用for循环迭代
1 | for x in range(3)) g = (x |
创建生成器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 | 1 a = |
在其他语言中,这种赋值要引入第三变量。不然第二条赋值结果会因为第一条赋值操作而改变。
上文中的test(num)
函数变为生成器很简单,只需要把函数的print(b)
换成yield b
1 | def test(num): |
如果一个函数定义中包含了关键字yield
,那么这个函数不再是一个普通的函数,而是一个生成器
调用结果,返回的是一个generator对象:
1 | 9) test( |
生成器的执行原理
在函数中添加了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()
循环计算下一个值。