在python中,代码不是越多越好,而是越少越好,代码越少,开发效率越高
切片:
取一个list和tuple的部分元素是非常常见的
>>>L=['a','b','c','d']
>>>L[0:3]
['a','b','c']
L[0:3]表示,从索引0开始取,直到索引3为止,但不包括索引3,即0,1,2,正好3个元素。
如果第一个索引是0,还可以省略:
>>>L[:3]
['a','b','c']
也可以从索引2取1个元素出来
>>>L[2:3]
['c']
同时支持倒数切片:
倒数第一个元素的索引是-1
>>>L[-2:]
['c','d']
>>>L[-2:-1]
['c']
切片操作十分有用,比如:
我们先创建一个0-99的数列
>>>L = list(range(100))
>>>L
[0,1,2,3,4,…99]
可以通过数列轻松取出某一段数列:
比如:
取前5个数
>>>L[:5]
[0,1,2,3,4]
取后5个数
>>>L[-5:]
[95,96,97,98,99]
前5-10个数:
>>>L[5:10]
[5,6,7,8,9]
前10个数,每两个取一个:
>>>L[:10:2]
[0,2,4,6,8]
所有数,每10个取一个:
>>>L[::10]
[0,10,20,30,40,50,60,70,80,90]
只写[:]可以复制一个list
>>>L[:]
[0,1,2,……99]
tuple也可以用切片操作,只是操作结果还是tuple:
>>>(0,1,2,3,4,5)[:3]
(0,1,2)
字符串也可以用切片操作,只是操作结果还是字符串:
>>>'ABCDEFG'[:3]
'ABC'
小结:有了切片操作,很多地方循环就不再需要了。
迭代:
如果给定一个list或者tuple,我们可以通过for循环来遍历这个list或者tuple,这种遍历我们称为迭代(Iteration)
很多语言比如c语言或者java语言,迭代是通过list下标完成的。
在python中,迭代是通过for…in来完成的,它的for循环抽象程度要高于java的for循环。因为python的for循环不仅可以作用在list或者tuple上,还可以作用在其它可迭代的对象上。
比如:
dict就可以迭代:
>>>d={'a':1,'b':2,'c':3}
>>>for key in d:
…print(key)
输出结果:
a
c
b
因为dict的存储不是按照list的方式顺序排列的,所以,迭代的结果顺序很可能不一样。
默认情况下,dict迭代的是key,如果要迭代value,可以用for value in d.value(),如果要同时迭代key和value,可以用 for k,v in d.items()
字符串也是可迭代对象,因此,也可以作用于for循环:
>>>for ch in 'ABC':
>>>print(ch)
输出结果:
A
B
C
所以,当我们使用for循环时,只要作用于一个可迭代对象,for循环就可以正常运行了,而我们不太关心该对象究竟是list还是其他数据类型。
那么如何判断一个对象是可迭代对象呢?
可以通过collections模块的Iterable类型判断:
>>>from collections import Iterable
>>>isinstance('abc',Iterable)
True
>>>isinstance([1,2,3],Iterable)
True
>>isinstance(123,Iterable)
False
如果要对list实现类似java那样的下标循环怎么办?
Python内置的enumerate函数可以将一个list变成索引-元素对,这样就可以在for循环中同时迭代索引和元素本身
>>>for i,value in enumerate(['A','B','C']):
>>>print(i,value)
输出结果:
0 A
1 B
2 C
列表生成式:
列表生成式,是python内置的非常简单且强大的可以用来创建list的生成式
比如:
要生成list[1,2,3,4,5]可以用list(range(1,6))
>>>list(range(1,6))
[1,2,3,4,5]
如果要生成[1x1,2x2,3x3,4x4,5x5]怎么做?
方法一:
循环:
>>>L =[]
>>> for x in range(1,6):
>>>L.append(x*x)
>>>L
[1,4,9,16,25]
上面的循环太繁琐,可以用列表生成式代替循环生成上面的list
>>>[x*x for x in range(1,6)]
[1,4,9,16,25]
写列表生成式时,把要生成的元素x*x放在前面,后面跟for循环,就可以将list创建出来了。
for循环后面还可以加上if判断:
比如:筛选出偶数的平方
>>>[x*x for in range(1,6) if x%2 ==0]
[4,16]
dict的items()可以同时迭代key和value:
>>>d={'x':'a','y':'b','z':'c'}
>>> for k,v in d.items()
>>>print(k,'=',v)
输出结果:
y = b
x = a
z = c
因此,dict可以列表生成式也可以使用两个变量生成list
>>>d={'x':'a','y':'b','z':'c'}
>>>[k + '=' + v for k,v in d.items()]
['y=b','x=a','z=c']
比如:
一个list中的所有字符串变成大写:
>>>L = ['HELLO','WORD']
>>>[s.lower() for s in L]
['hello','word']
生成器:
通过列表生成式,我们可以直接创建一个列表。但是由于内存限制,列表容量肯定是有限的。
当我们创建一个包含100万个元素的列表,若我们仅仅访问前面几个元素,那么后面绝大多数元素占用的空间都浪费了。
如果列表元素可以按照某种算法推算出来,那我们是否可以在循环过程中不断的推算出后续的元素。这样,我们就不必创见完整的list,从而节省了大量的空间。
在python中,这种一边循环一边计算的机制,称为生成器:generator
要创建一个generator,有很多种方法:
第一种:只要将列表生成式的[]改成(),就创建了一个generator
>>>g =(x*x for x in range(5))
如果要一个一个的打印出来,可以通过next()函数获得generator的下一个返回值:
>>>next(g)
0
每次调用next(g),就计算出g的下一个元素值,直到计算到最后一个元素,没有更多元素时,就会抛出StopIteration的错误
正确的方法是使用for循环,因为generator也是可迭代的对象:
>>>g =(x*x for x in range(5))
>>>for n in g:
>>>print(n)
02314
定义一个generator的另一个方法。如果一个函数定义包含yield关键字,那么这个函数就不再是一个普通函数,而是一个generator。
这里需要理解的是generator和函数的执行流程不一样。
函数的顺序执行,遇到return语句或者最后一行函数语句就返回。
而变成generator的函数,每次调用next()的时候执行,遇到yield语句就返回,再次执行从上次返回的yield语句处继续执行。generator函数的调用,实际返回一个generator对象。
迭代器:
我们知道,可以直接作用于,for循环的数据类型有以下几种:
一类是集合数据类型,如:list,tuple,dict,set,str
一类是generator,包括生成器和带yield的generator function
这些作用于for循环的对象统称为可迭代对象:Iterable
可以使用isinstance()判断一个对象是否是Iterable对象。
>>>from collections import Iterable
>>>isinstance([],Iterable)
True
>>>isinstance({},Iterable)
True
>>>isinstance('abc',Iterable)
True
>>>isinstance((x for x in range(10)),Iterable)
True
>>isinstance(50,Iterable)
False
生成器不但可以作用于for循环,还可以被next()函数调用并返回下一个值,直到最后抛出StopIteration错误异常表示无法继续返回下一个值了。
可以被next()函数调用并不断返回下一个值的对象称为迭代器:Iterator
可以使用isinstance()判断一个对象是否Iterator对象
>>>from collections import Iterable
>>>isinstance([],Iterable)
False
>>>isinstance({},Iterable)
False
>>>isinstance('abc',Iterable)
False
>>>isinstance((x for x in range(10)),Iterable)
True
生成器都是Iterator对象,但list、dict、str虽然是Iteratble,却不是Iterator。
把list、dict、str等变成Iterator可以使用iter()函数:
>>>isinstance(iter([]),Iterable)
True
>>>isinstance(iter({}),Iterable)
True
>>>isinstance(iter('abc'),Iterable)
True
为什么list,dict,str等数据类型不是Iterator?
这是因为Python的Iterator对象表示我一个数据流,甚至可以表示一个无限大的数据流,例如:自然数,而list是永远不可能全体自然数的。
小结:
凡是可以作用于for循环的对象都是Iterable类型;
凡是可作用于next()函数的对象都是Iterator,它们表示的是一个惰性计算的序列
集合数据类型如list、dict、str等是Iterable但不是Iterator,不过可以通过iter()函数获得Iterator对象
Python的for循环本质上就是通过不断调用next()函数实现的



