Python學習三——高階特性
https://www.liaoxuefeng.com/wiki/0014316089557264a6b348958f449949df42a6d3a2e542c000/0014317568446245b3e1c8837414168bcd2d485e553779e000
Python提供了切片(Slice)操作符
L[0:3]
表示,從索引0
開始取,直到索引3
為止,但不包括索引3
。即索引0
,1
,2
,正好是3個元素。
如果第一個索引是0
,還可以省略:
也可以從索引1開始,取出2個元素出來:
類似的,既然Python支援L[-1]
取倒數第一個元素,那麼它同樣支援倒數切片
只寫[:]
就可以原樣複製一個list
tuple也是一種list,唯一區別是tuple不可變。因此,tuple也可以用切片操作,只是操作的結果仍是tuple
字串'xxx'
也可以看成是一種list,每個元素就是一個字元。因此,字串也可以用切片操作,只是操作結果仍是字串
利用切片操作,實現一個trim()函式,去除字串首尾的空格,注意不要呼叫str的strip()
方法:
迭代
因為dict的儲存不是按照list的方式順序排列,所以,迭代出的結果順序很可能不一樣。
dict迭代的是key。如果要迭代value,可以用for value in d.values()
,如果要同時迭代key和value,可以用for k, v in d.items()
。
如果要對list實現類似Java那樣的下標迴圈怎麼辦?Python內建的enumerate
函式可以把一個list變成索引-元素對,這樣就可以在for
迴圈中同時迭代索引和元素本身:
請使用迭代查詢一個list中最小和最大值,並返回一個tuple:
列表生成式
for
迴圈其實可以同時使用兩個甚至多個變數,比如dict
的items()
可以同時迭代key和value:
因此,列表生成式也可以使用兩個變數來生成list:
最後把一個list中所有的字串變成小寫:
使用內建的isinstance
函式可以判斷一個變數是不是字串:
生成器
要建立一個generator,有很多種方法。第一種方法很簡單,只要把一個列表生成式的[]
改成()
,就建立了一個generator:
建立L
和g
的區別僅在於最外層的[]
和()
,L
是一個list,而g
是一個generator。
我們可以直接打印出list的每一個元素,但我們怎麼打印出generator的每一個元素呢?
如果要一個一個打印出來,可以通過next()
函式獲得generator的下一個返回值:
每次呼叫next(g)
,就計算出g
的下一個元素的值,直到計算到最後一個元素,沒有更多的元素時,丟擲StopIteration
的錯誤。
我們建立了一個generator後,基本上永遠不會呼叫next()
,而是通過for
迴圈來迭代它,並且不需要關心StopIteration
的錯誤。
generator非常強大。如果推算的演算法比較複雜,用類似列表生成式的for
迴圈無法實現的時候,還可以用函式來實現。
比如,著名的斐波拉契數列(Fibonacci),除第一個和第二個數外,任意一個數都可由前兩個數相加得到:
1, 1, 2, 3, 5, 8, 13, 21, 34, ...
上面的函式和generator僅一步之遙。要把fib
函式變成generator,只需要把print(b)
改為yield b
就可以了:
generator函式的“呼叫”實際返回一個generator物件:
這裡,最難理解的就是generator和函式的執行流程不一樣。函式是順序執行,遇到return
語句或者最後一行函式語句就返回。而變成generator的函式,在每次呼叫next()
的時候執行,遇到yield
語句返回,再次執行時從上次返回的yield
語句處繼續執行。
用for
迴圈呼叫generator時,發現拿不到generator的return
語句的返回值。如果想要拿到返回值,必須捕獲StopIteration
錯誤,返回值包含在StopIteration
的value
中:
不懂為何會出錯
楊輝三角練習:
把每一行看做一個list,試寫一個generator,不斷輸出下一行的list:
迭代器
我們已經知道,可以直接作用於for
迴圈的資料型別有以下幾種:
一類是集合資料型別,如list
、tuple
、dict
、set
、str
等;
一類是generator
,包括生成器和帶yield
的generator function。
這些可以直接作用於for
迴圈的物件統稱為可迭代物件:Iterable
。
可以使用isinstance()
判斷一個物件是否是Iterable
物件:
而生成器不但可以作用於for
迴圈,還可以被next()
函式不斷呼叫並返回下一個值,直到最後丟擲StopIteration
錯誤表示無法繼續返回下一個值了。
可以被next()
函式呼叫並不斷返回下一個值的物件稱為迭代器:Iterator
。
可以使用isinstance()
判斷一個物件是否是Iterator
物件:
生成器都是Iterator
物件,但list
、dict
、str
雖然是Iterable
,卻不是Iterator
。
把list
、dict
、str
等Iterable
變成Iterator
可以使用iter()
函式:
你可能會問,為什麼list
、dict
、str
等資料型別不是Iterator
?
這是因為Python的Iterator
物件表示的是一個數據流,Iterator物件可以被next()
函式呼叫並不斷返回下一個資料,直到沒有資料時丟擲StopIteration
錯誤。可以把這個資料流看做是一個有序序列,但我們卻不能提前知道序列的長度,只能不斷通過next()
函式實現按需計算下一個資料,所以Iterator
的計算是惰性的,只有在需要返回下一個資料時它才會計算。
凡是可作用於for
迴圈的物件都是Iterable
型別;
凡是可作用於next()
函式的物件都是Iterator
型別,它們表示一個惰性計算的序列;
集合資料型別如list
、dict
、str
等是Iterable
但不是Iterator
,不過可以通過iter()
函式獲得一個Iterator
物件。