1. 程式人生 > >再一次重新學習Python——高階特性

再一次重新學習Python——高階特性

  • 切片

L[0:3]表示,從索引0開始取,直到索引3為止,但不包括索引3。即索引0,1,2,正好是3個元素。如果第一個索引是0,還可以省略。

同樣支援倒數切片

>>> L = ['Michael', 'Sarah', 'Tracy', 'Bob', 'Jack']
>>> L[-2:]
['Bob', 'Jack']
>>> L[-2:-1]
['Bob']

記住倒數第一個元素的索引是-1

前10個數,每兩個取一個:

>>> L[:10:2]
[0, 2, 4, 6, 8]

甚至什麼都不寫,只寫[:]就可以原樣複製一個list。

tuple也是一種list,唯一區別是tuple不可變。因此,tuple也可以用切片操作,只是操作的結果仍是tuple:

>>> (0, 1, 2, 3, 4, 5)[:3]
(0, 1, 2)

字串'xxx'或Unicode字串u'xxx'也可以看成是一種list,每個元素就是一個字元。因此,字串也可以用切片操作,只是操作結果仍是字串:

>>> 'ABCDEFG'[:3]
'ABC'
>>> 'ABCDEFG'[::2]
'ACEG'
  • 迭代

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.itervalues(),如果要同時迭代key和value,可以用for k, v in d.iteritems()

由於字串也是可迭代物件,因此,也可以作用於for迴圈:

>>> for ch in 'ABC':
...     print ch
...
A
B
C

 通過collections模組的Iterable型別判斷某物件是否為可迭代的物件。

Python內建的enumerate

函式可以把一個list變成索引-元素對,這樣就可以在for迴圈中同時迭代索引和元素本身:

>>> for i, value in enumerate(['A', 'B', 'C']):
...     print i, value
...
0 A
1 B
2 C

上面的for迴圈裡,同時引用了兩個變數,在Python裡是很常見的,比如下面的程式碼:

>>> for x, y in [(1, 1), (2, 4), (3, 9)]:
...     print x, y
...
1 1
2 4
3 9

 enumerate() 方法的語法:

enumerate(sequence, [start=0])

引數

  • sequence -- 一個序列、迭代器或其他支援迭代物件。
  • start -- 下標起始位置。

返回值

返回 enumerate(列舉) 物件。

  •  列表生成式

>>> [x * x for x in range(1, 11)]
[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]

for迴圈後面還可以加上if判斷,這樣我們就可以篩選出僅偶數的平方:

>>> [x * x for x in range(1, 11) if x % 2 == 0]
[4, 16, 36, 64, 100]

還可以使用兩層迴圈,可以生成全排列:

>>> [m + n for m in 'ABC' for n in 'XYZ']
['AX', 'AY', 'AZ', 'BX', 'BY', 'BZ', 'CX', 'CY', 'CZ']

兩個變數 

>>> d = {'x': 'A', 'y': 'B', 'z': 'C' }
>>> [k + '=' + v for k, v in d.iteritems()]
['y=B', 'x=A', 'z=C']

把一個list中所有的字串變成小寫:

>>> L = ['Hello', 'World', 'IBM', 'Apple']
>>> [s.lower() for s in L]
['hello', 'world', 'ibm', 'apple']
  • 生成器

如果列表元素可以按照某種演算法推算出來,那我們是否可以在迴圈的過程中不斷推算出後續的元素呢?這樣就不必建立完整的list,從而節省大量的空間。在Python中,這種一邊迴圈一邊計算的機制,稱為生成器(Generator)。 

建立生成器的方法

第一種方法很簡單,只要把一個列表生成式的[]改成(),就建立了一個generator:

>>> L = [x * x for x in range(10)]
>>> L
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
>>> g = (x * x for x in range(10))
>>> g
<generator object <genexpr> at 0x104feab40>

建立Lg的區別僅在於最外層的[]()L是一個list,而g是一個generator。

怎麼打印出generator的每一個元素呢?

如果要一個一個打印出來,可以通過generator的next()方法:

>>> g.next()
0
>>> g.next()
1

正確的方法是使用for迴圈,因為generator也是可迭代物件

g = (x * x for x in range(10))
>>> for n in g:
        print n

如果一個函式定義中包含yield關鍵字,那麼這個函式就不再是一個普通函式,而是一個generator

def fib(max):
    n, a, b = 0, 0, 1
    while n < max:
        yield b
        a, b = b, a + b
        n = n + 1

最難理解的就是generator和函式的執行流程不一樣。函式是順序執行,遇到return語句或者最後一行函式語句就返回。而變成generator的函式,在每次呼叫next()的時候執行,遇到yield語句返回,再次執行時從上次返回的yield語句處繼續執行。 

要理解generator的工作原理,它是在for迴圈的過程中不斷計算出下一個元素,並在適當的條件結束for迴圈。對於函式改成的generator來說,遇到return語句或者執行到函式體最後一行語句,就是結束generator的指令,for迴圈隨之結束。