一造壮、高級特性切片
對這種經(jīng)常取指定索引范圍的操作渡讼,用循環(huán)十分繁瑣,因此耳璧,Python提供了切片(Slice)操作符成箫,能大大簡化這種操作。
L = ['java','php','c','python']
print(L[0:2])
tuple也是一種list旨枯,唯一區(qū)別是tuple不可變蹬昌。因此,tuple也可以用切片操作攀隔,只是操作的結(jié)果仍是tuple:
字符串'xxx'也可以看成是一種list皂贩,每個元素就是一個字符栖榨。因此,字符串也可以用切片操作明刷,只是操作結(jié)果仍是字符串:
在很多編程語言中婴栽,針對字符串提供了很多各種截取函數(shù)(例如,substring)辈末,其實(shí)目的就是對字符串切片愚争。Python沒有針對字符串的截取函數(shù),只需要切片一個操作就可以完成挤聘,非常簡單
二轰枝、迭代
如果給定一個list或tuple,我們可以通過for循環(huán)來遍歷這個list或tuple组去,這種遍歷我們稱為迭代(Iteration)鞍陨。
默認(rèn)情況下,dict迭代的是key从隆。如果要迭代value诚撵,可以用for value in d.values(),如果要同時迭代key和value键闺,可以用for k, v in d.items()砾脑。
d = {'a':1,'b':2,'c':3}
for key in d:
print(key)
Python的for循環(huán)不僅可以用在list或tuple上,還可以作用在其他可迭代對象上
字符串也是可迭代對象艾杏,因此,也可以作用于for循環(huán)
for ch in 'ABC':
print(ch)
三盅藻、列表生成式
列表生成式即List Comprehensions购桑,是Python內(nèi)置的非常簡單卻強(qiáng)大的可以用來創(chuàng)建list的生成式。
list1 = list(range(1,11))
print(list1)
輸出結(jié)果:[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
如果要生成[1x1, 2x2, 3x3, ..., 10x10]怎么做氏淑?方法一是循環(huán):
L = []
for x in range(1,11):
L.append(x*x)
print(L)
但是循環(huán)太繁瑣勃蜘,而列表生成式則可以用一行語句代替循環(huán)生成上面的list:
print([x*x for x in range(1,11)])
寫列表生成式時,把要生成的元素x * x放到前面假残,后面跟for循環(huán)缭贡,就可以把list創(chuàng)建出來,十分有用辉懒,多寫幾次阳惹,很快就可以熟悉這種語法。
但是循環(huán)太繁瑣眶俩,而列表生成式則可以用一行語句代替循環(huán)生成上面的list:
print([x-x for x in range(1,11)])
for循環(huán)后面還可以加上if判斷莹汤,這樣我們就可以篩選出僅偶數(shù)的平方
print([x*x for x in range(1,11) if x % 2 == 0])
還可以使用兩層循環(huán),可以生成全排列:
print([m + n for m in 'ABC' for n in 'zxc'])
運(yùn)用列表生成式颠印,可以寫出非常簡潔的代碼纲岭。例如抹竹,列出當(dāng)前目錄下的所有文件和目錄名,可以通過一行代碼實(shí)現(xiàn):
import os#導(dǎo)入os模塊
print(d for d in os.listdir('.'))#os.listdir可以累出文件和目錄
for 循環(huán)其實(shí)可以同時使用兩個甚至更多個變量止潮,比如dict的items()可以同時迭代key和value
d = {'x':'X','y':'Y','z':'Z'}
for k,v in d.items():
print(k,'=',v)
因此窃判,列表生成式也可以使用兩個變量來生成list:
print([k + '=' + v for k, v in d.items()])
最后把一個list中的所有字符串變成小寫
L = ['JavA','PHp','PYthon']
print([s.lower() for s in L])
如果list中既包含字符串,又包含整數(shù)喇闸,由于非字符串類型沒有l(wèi)ower()方法袄琳,所以列表生成式會報錯:
使用內(nèi)建對象isinstance函數(shù)可以判斷一個變量是不是字符串:
J = ['Hello','Java',56,'Php']
print([s.lower() for s in J if isinstance(s,str)])
生成器
通過列表生成式,我們可以直接創(chuàng)建一個列表仅偎。但是跨蟹,受到內(nèi)存限制,列表容量肯定是有限的橘沥。而且窗轩,創(chuàng)建一個包含100萬個元素的列表,不僅占用很大的存儲空間座咆,如果我們僅僅需要訪問前面幾個元素痢艺,那后面絕大多數(shù)元素占用的空間都白白浪費(fèi)了。
所以介陶,如果列表元素可以按照某種算法推算出來堤舒,那我們是否可以在循環(huán)的過程中不斷推算出后續(xù)的元素呢?這樣就不必創(chuàng)建完整的list哺呜,從而節(jié)省大量的空間舌缤。在Python中,這種一邊循環(huán)一邊計算的機(jī)制某残,稱為生成器:generator国撵。
g = (x*x for x in range(10))
for n in g:
print(n)
所以,我們創(chuàng)建了一個generator后玻墅,基本上永遠(yuǎn)不會調(diào)用next()介牙,而是通過for循環(huán)來迭代它,并且不需要關(guān)心StopIteration的錯誤
generator非常強(qiáng)大澳厢。如果推算的算法比較復(fù)雜环础,用類似列表生成式的for循環(huán)無法實(shí)現(xiàn)的時候,還可以用函數(shù)來實(shí)現(xiàn)剩拢。
比如线得,著名的斐波拉契數(shù)列(Fibonacci),除第一個和第二個數(shù)外徐伐,任意一個數(shù)都可由前兩個數(shù)相加得到:
def fib(max):
n,a,b = 0,0,1
while n < max:
print(b)
#注意框都,賦值語句
a,b = b,a+b #相當(dāng)于:t = (b, a + b) # t是一個tuple a = t[0] b = t[1]
n = n + 1
return 'done'
print(fib(6))
這就是定義generator的另一種方法。如果一個函數(shù)定義中包含yield關(guān)鍵字,那么這個函數(shù)就不再是一個普通函數(shù)魏保,而是一個generator:
def fib(max):
n,a,b = 0,0,1
while n < max:
yield(b)
#注意熬尺,賦值語句
a,b = b,a+b #相當(dāng)于:t = (b, a + b) # t是一個tuple a = t[0] b = t[1]
n = n + 1
return 'done'
for x in fib(6):
print(x)
但是用for循環(huán)調(diào)用generator時,發(fā)現(xiàn)拿不到generator的return語句的返回值谓罗。如果想要拿到返回值粱哼,必須捕獲StopIteration錯誤,返回值包含在StopIteration的value中:
g = fib(6)
while True:
try:
x = next(g)
print("g",x)
except StopIteration as e:
#捕獲當(dāng)前異常
print('Generator return value:',e.value)
break
迭代器
我們已經(jīng)知道檩咱,可以直接作用于for循環(huán)的數(shù)據(jù)類型有以下幾種:
一類是集合數(shù)據(jù)類型揭措,如list、tuple刻蚯、dict绊含、set、str等炊汹;
一類是generator躬充,包括生成器和帶yield的generator function。
這些可以直接作用于for循環(huán)的對象統(tǒng)稱為可迭代對象:Iterable讨便。
可以使用isinstance()判斷一個對象是否是Iterable對象:
from collections import Iterable
print(isinstance([],Iterable)) true
print(isinstance({},Iterable)) true
print(isinstance('abc',Iterable)) true
而生成器不但可以作用于for循環(huán)充甚,還可以被next()函數(shù)不斷調(diào)用并返回下一個值,直到最后拋出StopIteration錯誤表示無法繼續(xù)返回下一個值了霸褒。
可以被next()函數(shù)調(diào)用并不斷返回下一個值的對象稱為迭代器:Iterator伴找。
生成器都是Iterator對象,但list废菱、dict技矮、str雖然是Iterable,卻不是Iterator殊轴。
把list穆役、dict、str等Iterable變成Iterator可以使用iter()函數(shù)
isinstance(iter([]), Iterator)
True
isinstance(iter('abc'), Iterator)
True
為什么list梳凛、dict、str等數(shù)據(jù)類型不是Iterator梳杏?
這是因為Python的Iterator對象表示的是一個數(shù)據(jù)流韧拒,Iterator對象可以被next()函數(shù)調(diào)用并不斷返回下一個數(shù)據(jù),直到?jīng)]有數(shù)據(jù)時拋出StopIteration錯誤十性∨岩纾可以把這個數(shù)據(jù)流看做是一個有序序列,但我們卻不能提前知道序列的長度劲适,只能不斷通過next()函數(shù)實(shí)現(xiàn)按需計算下一個數(shù)據(jù)楷掉,所以Iterator的計算是惰性的,只有在需要返回下一個數(shù)據(jù)時它才會計算霞势。
Iterator甚至可以表示一個無限大的數(shù)據(jù)流烹植,例如全體自然數(shù)斑鸦。而使用list是永遠(yuǎn)不可能存儲全體自然數(shù)的。
小結(jié)
凡是可作用于for循環(huán)的對象都是Iterable類型草雕;
凡是可作用于next()函數(shù)的對象都是Iterator類型巷屿,它們表示一個惰性計算的序列;
集合數(shù)據(jù)類型如list墩虹、dict嘱巾、str等是Iterable但不是Iterator,不過可以通過iter()函數(shù)獲得一個Iterator對象诫钓。