用 python 差很少半年多了,從去年暑假開始接觸,從開始的懵逼,到寫了一些小爬蟲總算入門以後,許多做業也是能用 python 就用 python,基本拋棄了 C++。可是仍是有些過於急躁了,可以寫一些簡短的代碼,可是對於 python 的不少特性都不知道或者忘記了,這裏回去廖大教程複習一下,順便記錄下我以爲比較重要的地方。python
本文主要記錄廖大教程中高級特性這一節的內容,並寫下個人一些理解。在我看來,這些特性是很 pythonic 的,用在代碼中頗有 bigger 啊~算法
切片和迭代就不說了,這裏直接先看一下列表生成式吧,從名字就能大概猜出這是生成列表的一些方法,好比:如何生成[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
爲何要使用生成器?廖大的教程中說得很詳細,這裏再簡述一下:
由於列表的內容放在內存中,而受到內存限制,列表的容量有限。
若是咱們只訪問極少的元素,那麼存在極大的空間浪費。
而生成器能夠一邊迭代一邊計算下一個值,理論上,該過程能夠無限進行下去,而且不會佔用大量內存。
這裏只是簡單介紹一下,更詳細的請 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
可直接做用於 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 什麼的是不可能這樣的。
過了個寒假沒碰代碼,至關於複習了一遍啊,其實這裏說到的特性是很淺顯的,理解起來不難,等所有差很少複習完還得再深刻一點,理解更多才行。
以上~