1、切片
列表或元祖中取部分元素很常见。比如:
In [200]: list=['xjm','xyl','lxh','pzq'] In [201]: list[:3] Out[201]: ['xjm', 'xyl', 'lxh']
说明:这里我取了前三个,[:3]和[0:3]一样。0可省略
注意:索引是从零开始,以-1结束。
切片操作十分有用。我们来创建一个0–99的数列:
In [202]: l=list(range(0,100)) --------------------------------------------------------------------------- TypeError Traceback (most recent call last) <ipython-input-202-7935b62f0794> in <module>() ----> 1 l=list(range(0,100)) TypeError: 'list' object is not callable In [203]: del list In [204]: l=list(range(0,100))
说明:很明显看到报错了,因为list之前被赋值了。导致创建列表时,引用对象不存在。这时删除就行。
我们来取前20个数:
In [206]: l[:10]
Out[206]: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
后十个数:
In [207]: l[-10:]
Out[207]: [90, 91, 92, 93, 94, 95, 96, 97, 98, 99]
第20-30个数:
In [208]: l[19:30]
Out[208]: [19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29]
前十个数。步长为2:
In [209]: l[:10:2]
Out[209]: [0, 2, 4, 6, 8]
所有数,步长为5:
In [210]: l[::5]
Out[210]: [0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85, 90, 95]
元祖tuple也类似:
In [211]: t=1,2,3,4,5,'xjm' In [212]: t[0:2] Out[212]: (1, 2)
字符串也是如此:
In [213]: 'xjmloveyou'[:7] Out[213]: 'xjmlove'
2、迭代
如果给定一个list或tuple,我们可以通过for循环来遍历。这种遍历称为迭代。
In [225]: d=dict(a=1,b=2,c=3) In [226]: d Out[226]: {'a': 1, 'b': 2, 'c': 3} In [227]: for key in d: ...: print(key) ...: a b c In [228]: for v in d.values(): ...: print(v) ...: 1 2 3 In [229]: for k,v in d.items(): ...: print(k,v) ...: a 1 b 2 c 3
说明:字典默认的是迭代key。如果要迭代value,可用d.values(),如果键值同时迭代。则可用d.items().
字符串也是可迭代对象。同样for循环:
In [230]: for char in 'xjm love you lalala': ...: print(char) ...: x j m l o v e y o u l a l a l a
所以,当我们使用for循环时,只要作用于可迭代对象,for循环就可以运行,而我们不太关心该对象究竟是list还是其他数据类型。
那么,如何判断一个对象是可迭代对象呢?通过collection模块的iterable类型来判断:
In [231]: from collections import Iterable In [232]: isinstance('xjm',Iterable) Out[232]: True In [233]: isinstance('[1,2,3]',Iterable) Out[233]: True In [234]: isinstance(123,Iterable) Out[234]: False In [235]: isinstance(1,2,3,Iterable) --------------------------------------------------------------------------- TypeError Traceback (most recent call last) <ipython-input-235-1ee68315817a> in <module>() ----> 1 isinstance(1,2,3,Iterable) TypeError: isinstance expected 2 arguments, got 4 In [236]: isinstance((1,2,3),Iterable) Out[236]: True
说明:字典,元祖,列表,字符串都是True。整数是False。
Python内置的enumerate函数可以把一个list变成索引-元素对,这样就可以在for循环中同时迭代索引和元素本身:
In [237]: for i,v in enumerate(['a','b','c']): ...: print(i,v) ...: 0 a 1 b 2 c
In [239]: for i,j in [(1,2),(3,4),(5,6)]: ...: print(i,j) 1 2 3 4 5 6
In [240]: for i,j in [[1,2],[3,4],[5,6]]: ...: print(i,j) 1 2 3 4 5 6
练习:请使用迭代查找一个list中最小和最大值,并返回一个tuple:
In [5]: def find(list): ...: if list !=[]: ...: max,min = list[0],list[0] ...: for i in list: ...: if max < i: ...: max = i ...: if min > i: ...: min = i ...: return(min,max) ...: else: ...: print('这是一个l空列表,无法比较') In [6]: find([1,2,3,4,5,6,7,8,9]) Out[6]: (1, 9) In [7]: find([]) 这是一个l空列表,无法比较
3、列表生成式
举个例子,生成[1,2,3,4,5,6,7,8,9,10],可以用list(range(1,11))创建。
In [9]: list(range(1,11))
Out[9]: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
但是,如果要生成[1,4,9,16,25,36,49]这种列表呢?你应该想到了循环:
In [10]: list=[] In [12]: for i in range(1,8): ...: list.append(i**2) ...: In [13]: list Out[13]: [1, 4, 9, 16, 25, 36, 49]
太繁琐啦,有没有简单快速的方法呢?如下:
In [14]: list=[x*x for x in range(1,8)] In [15]: list Out[15]: [1, 4, 9, 16, 25, 36, 49]
还可以用到lambda函数:
In [28]: res=map(lambda x:x*x,range(1,8))
In [29]: list(res)
Out[30]: [1, 4, 9, 16, 25, 36, 49]
这里我想错了,因为map在python2是直接返回一个列表,而python3是一个迭代对象。可以用list直接转。
还可以在后面加条件:
In [36]: [x*x for x in range(1,10) if x % 2==0] Out[36]: [4, 16, 36, 64]
还可以使用两层循环,可以生成全排列:
In [37]: [x+y for x in "abc" for y in"ABC"] Out[37]: ['aA', 'aB', 'aC', 'bA', 'bB', 'bC', 'cA', 'cB', 'cC']
把列表的字符串全变为小写:
In [38]: l=['Hello','world','IBM','Google'] In [39]: a=[s.lower() for s in l] In [40]: a Out[40]: ['hello', 'world', 'ibm', 'google']
4、生成器
通过列表生成式可以直接创建一个列表,但是毕竟内存有限制,容量有限。所以有一种边循环边计算的机制,称为生成器:generator.
创建generator:
把列表生成式的方括号改为括号就行啦!
In [45]: g=(x*x for x in (1,2,3)) In [46]: type(g) Out[46]: generator In [47]: next(g) Out[47]: 1 In [48]: next(g) Out[48]: 4 In [49]: next(g) Out[49]: 9
说明:当没有下一个元素时,跑出StopIteration的异常。
其实,generator也是一个可迭代对象,所以可以通过for循环。
In [56]: for i in g: ...: print(i) 1 4 9
下面来打印一下fbi:
In [60]: def fbi(max): ...: n,a,b=0,0,1 ...: while n<max: ...: print(b) ...: a,b=b,a+b ...: n+=1 ...: return 'done' ...: In [61]: fbi(1) 1 Out[61]: 'done' In [62]: fbi(8) 1 1 2 3 5 8 13 21 Out[62]: 'done'
要想把这种逻辑变成generator。只要把print改成yield就可以了,就不再是普通函数,而是一个generator。
简单例子,依次返回数字1,3,5:
In [63]: def odd(): ...: yield 1 ...: yield 2 ...: yield 3 ...: In [64]: o=odd() In [65]: o Out[65]: <generator object odd at 0x000001798E9FEA40>
然后用next取值:
In [66]: next(o) Out[66]: 1 In [67]: next(o) Out[67]: 2 In [68]: next(o) Out[68]: 3
回到之前的fib。我们可以使用下面代码来实现:
In [82]: g=fbi(6) In [83]: while True: ...: try: ...: x=next(g) ...: print('g',x) ...: except StopIteration as e: ...: print('结束取值',e.value) ...: break ...: g 1 g 1 g 2 g 3 g 5 g 8 结束取值 done
5、迭代器
我们已经知道,可以直接作用于for循环的数据类型有以下几种:
一类是集合数据类型,如list、tuple、dict、set、str等;
一类是generator,包括生成器和带yield的generator 函数。
这些可以直接作用于for循环的对象统称为可迭代对象:Iterable。可以用isinstance()来判断。
而生成器不但可以作用于for循环,还可以被next()取值。
Iterable变成Iterator可以使用iter()函数:
In [85]: isinstance(iter([1,2,3]),Iterator)
Out[85]: True
总结:
- 可以被next()函数调用并不断返回下一个值的对象称为迭代器:Iterator。
- 可以使用isinstance()判断一个对象是否是Iterator对象和Iterable。
原创文章,作者:ItWorker,如若转载,请注明出处:https://blog.ytso.com/7557.html