[python] 關於 python 的一些高級特性

前言

用 python 差很少半年多了,從去年暑假開始接觸,從開始的懵逼,到寫了一些小爬蟲總算入門以後,許多做業也是能用 python 就用 python,基本拋棄了 C++。可是仍是有些過於急躁了,可以寫一些簡短的代碼,可是對於 python 的不少特性都不知道或者忘記了,這裏回去廖大教程複習一下,順便記錄下我以爲比較重要的地方。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 判斷,例如:code

>>> [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 < 'C' for n in 'XYZ' if n < 'Z']
['AX', 'AY', 'BX', 'BY']
>>> [m + n for m in 'ABC' for n in 'XYZ' if n < 'Z' and m < 'C']
['AX', 'AY', 'BX', 'BY']

也能夠同時在一個 for 語句中迭代多個變量,好比dict的items()能夠同時迭代key和value:get

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

差很少就是這樣了~generator

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

生成器(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 'done'

關於 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 什麼的是不可能這樣的。

總結

過了個寒假沒碰代碼,至關於複習了一遍啊,其實這裏說到的特性是很淺顯的,理解起來不難,等所有差很少複習完還得再深刻一點,理解更多才行。

以上~

相關文章
相關標籤/搜索