Python學習之高階特性詳解

2021-07-26 21:06:52 字數 3870 閱讀 1683

列表生成式(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 < '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:

>>> d = >>> [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

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

>>> for i in g:... print(i)

...0149162536496481>>> for i in g:... print(i)

...>>> next(g)

traceback (most recent call last):

file "", line 1, in 

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

總結過了個寒假沒碰**,相當於複習了一遍啊,其實這裡說到的特性是很淺顯的,理解起來不難,等全部差不多複習完還得再深入一點,理解更多才行。

python學習之高階特性

切片 對列表 元組 字串 字典取中間的一部分,在c中一般是通過for迴圈拷貝 memcpy strcat等操作。而python提供了更方便的切片操作符 m n 前閉後開,如果從0取m可以省略 如果只用 就是切整片 也可以從尾端切片 m 前後的閉區間。列表生成式 list range m,n 構造乙個...

Python之高階特性(2)

一 列表生成式 1 生成abc與def的全排列 2 1 輸出列表裡的名字 並且第乙個字母大寫 2 當列表裡有名字是非法字元時候,輸出列表裡的名字 並且第乙個字母大寫 3 找出指定目錄下以.log結尾的檔案 import os模組 os.listdir 檔名 檢視目錄下面的所有檔案 二 生成器 為什麼...

Python自學之高階語法特性

1 切片 切片用於提取一組資料list tuple等中的一部分,個人感覺和matlab語法很相似,例如l 0 3 表示取l 0 l 1 l 2 l 3 與上面等價,初始或者結束為首尾位置,則可以縮寫 l 2 0 表示取倒數第乙個l 1 和倒數第二個l 2 l 2 與上面等價 l 0 5 2 表示以2...