首頁 >後端開發 >Python教學 >關於 python 的一些高階特性

關於 python 的一些高階特性

高洛峰
高洛峰原創
2017-02-15 14:45:291003瀏覽

前言

用 python 差不多半年多了,從去年暑假開始接觸,從開始的懵逼,到寫了一些小爬蟲總算入門之後,許多作業也是能用 python 就用 python,基本拋棄了 C++。但還是有些過於急躁了,能夠寫一些簡短的程式碼,但是對於 python 的很多特性都不知道或者忘記了,這裡回去廖大教程複習一下,順便記錄下我覺得比較重要的地方。

開始

本文主要記錄廖大教程中高級特性這一節的內容,並寫下我的一些理解。在我看來,這些特性是很pythonic 的,用在程式碼中很有bigger 啊~

列表生成式(List Comprehensions)

切片和迭代就不說了,這裡直接先看一下列表生成式吧,從名字就能大概猜出這是產生清單的一些方法,例如:如何產生[1*1, 2*2, ... ,10*10]?可以用循環不斷在列表尾部添加元素,如果使用pythonic 的方法,也就是列表生成式,則是:

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

後面還能跟上if 判斷,例如:

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

這樣,本來需要使用循環寫4, 5行的程式碼,使用一行就解決了,直覺明了。

還能使用兩個 for 迴圈產生全排列:

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

這樣如何加入 if 判斷呢?可以在每個for 語句後面加,或者在最後加上:

>>> [m + n for m in 'ABC' if m < &#39;C&#39; for n in &#39;XYZ&#39; if n < &#39;Z&#39;]
[&#39;AX&#39;, &#39;AY&#39;, &#39;BX&#39;, &#39;BY&#39;]
>>> [m + n for m in 'ABC' for n in 'XYZ' if n < &#39;Z&#39; and m < &#39;C&#39;]
[&#39;AX&#39;, &#39;AY&#39;, &#39;BX&#39;, &#39;BY&#39;]

也可以同時在一個for 語句中迭代多個變量,例如dict的items()可以同時迭代key和value:

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

差不多就是這樣了~

但是以前總是寫C++ ,這種思維模式很難改過來,只能慢慢在使用中熟悉這種語法,習慣了就能夠在下意識中寫出來了。

生成器(Generator)

為什麼要使用生成器?廖大的教學中說得很詳細,這裡再簡述一下:

  1. 因為列表的內容放在記憶體中,而受到記憶體限制,列表的容量有限。

  2. 如果我們只訪問極少的元素,那麼存在極大的空間浪費。

  3. 而生成器可以一邊迭代一邊計算下一個值,理論上,該過程可以無限進行下去,並且不會佔用大量內存。

這裡只是簡單介紹一下,更詳細的請 Google 哈~

如何創建生成器?第一種方法類似前面講到的列表產生式,只需要將[]改為()即可:

>>> 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 0x1022ef630>

可以看到,方法上大致相同,[]得到的是一個已經得到所有值的列表,()得到的是一個生成器,它們都能使用for 循環來迭代,但是生成器不能使用下標訪問,並且只能被迭代一次,再次迭代則會有StopIteration 的異常:

>>> for i in g:
...     print(i)
...
0
1
4
9
16
25
36
49
64
81
>>> for i in g:
...     print(i)
...
>>> next(g)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
StopIteration

不過當我們創建了一個generator後,基本上永遠不會呼叫next(),而是透過for循環來迭代它,並且不需要關心StopIteration的錯誤。

如果推算的演算法比較複雜,用類似列表生成式的for循環無法實現的時候,還可以用函數來實現,比如,著名的斐波那契數列:

def fib(max):
    n, a, b = 0, 0, 1
    while n < max:
        yield b
        a, b = b, a + b
        n = n + 1
    return &#39;done&#39;

關於yield 這個關鍵字,我在剛學python 的時候也糾結了很久,直到看到生成器的時候才大致明白,大家搜尋一下就能大致明白了,我覺得這東西說起來麻煩,只說一兩句又怕說錯。廖大的教學中是這樣說的:

函數是順序執行,遇到return語句或最後一行函數語句就回傳。而變成generator的函數,在每次呼叫next()的時候執行,遇到yield語句返回,再次執行時從上次返回的yield語句處繼續執行。

可能有點難理解,不過明白了就很好說了。

當然,函數中還可以加入 return,在一個 generator function 中,如果沒有 return,則預設執行至函數完畢,如果在執行過程中 return,則直接拋出 StopIteration 終止迭代。

例如上面的例子,我們在迭代時發現並沒有出現'done' 這串字符,是因為return 的值被當作Exception Value 了,如果要顯示出來,則可以這樣:

>>> g = fib(6)
>>> while True:
...     try:
...         x = next(g)
...         print('g:', x)
...     except StopIteration as e:
...         print('Generator return value:', e.value)
...         break
...
g: 1
g: 1
g: 2
g: 3
g: 5
g: 8
Generator return value: done

迭代器(Iterator )

可直接作用於for 迴圈的物件稱為可迭代對象,可以用isinstance() 函數判斷是否為可迭代對象:

>>> from collections import Iterable
>>> isinstance([], Iterable)
True
>>> isinstance({}, Iterable)
True
>>> isinstance('abc', Iterable)
True
>>> isinstance((x for x in range(10)), Iterable)
True
>>> isinstance(100, Iterable)
False

而可以被next()函數呼叫並不斷傳回下一個值的對象稱為迭代器:Iterator。當然,仍然可以使用isinstance()判斷一個物件是否是Iterator物件:

>>> from collections import Iterator
>>> isinstance((x for x in range(10)), Iterator)
True
>>> isinstance([], Iterator)
False
>>> isinstance({}, Iterator)
False
>>> isinstance('abc', Iterator)
False

透過上面兩個例子,可以這樣理解:生成器和list,tuple,str 等都是Iterable 對象,生成器同時還是Iterator 對象,而list 等不是。那麼能否直接將 Iterable 物件轉換成 Iterator 物件呢?

可以使用iter()函數:

>>> isinstance(iter([]), Iterator)
True
>>> isinstance(iter('abc'), Iterator)
True

其实,Iterator 对象表示的是一个数据流,我们可以把这个数据流看做是一个有序序列,但却不能提前知道序列的长度,只能不断通过next()函数实现按需计算下一个数据,所以 Iterator 的计算是惰性的,只有在需要返回下一个数据时它才会计算。Iterator甚至可以表示一个无限大的数据流,但 list,tuple 什么的是不可能这样的。

更多关于 python 的一些高级特性相关文章请关注PHP中文网!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn