2018年4月28日 星期六

Python筆記:程式結構

迴圈

在Python中有個While/For迴圈搭配else的奇特用法(至少我沒有印象在Java, C/C++有看過),主要是在迴圈正常結束(沒有因為break而提早結束)時,進入到else的區塊中執行程式碼:

>>>pos = 1
>>>while pos < 5:
            if pos == 7:
                   break
            pos++
       else:
               #do nothing

以上展示了一個一定會進入else區塊的範例,因為pos永遠不會等於7,所以一定不會提早結束迴圈。else內可以放入只有迴圈正常結束才會執行的code。在for迴圈的使用方式也是一樣。

 迭代

1. zip()函式可以協助我們並行地迭代多個序列:

>>> animals = ['Dog', 'Cat', 'Elephant']
>>> colors = ['Blue', 'Yellow', 'Black']
>>> for animal, color in zip(animals, colors):
                 print( 'animal: ', animal, 'is in', color )
zip()回傳的是一個可迭代(iterable)的合併值,我們可以直接把此值轉換為list, dict...
2. range(start, stop, step)可以用來產生[start, stop)範圍的整數,並且每次數值會變動step的量。

生成式

1. list生成式:[ 運算式 for 項目 in 可迭代項目 ]

>>> mlist = [ num-1 for num in range(4,8) if num not 5 ]
>>> mlist
[3, 4, 6]

>>> a = range(2, 5)
>>> b = range(5,8)
>>> c = [(d,e) for d in a for e in b]
>>> c
(2, 5)
(2, 6)
(2, 7)
(3, 5)
(3, 6)
(3, 7)
(4, 5)
(4, 6)
(4, 7)

2. dict生成式:{鍵運算式 :值運算式 for 運算式 in 可迭代項目}

>>> word = 'letters'
>>> letter_counts = {letter: word.count(letter) for letter in set(word)}
>>> letter_counts
{'l': 1, 'e': 2, 't': 2, 'r': 1, 's': 1}

3. set生成式:{運算式 for 運算式 in 可迭代項目}

幾乎和list生成式一樣,只是換成了大括號。

4. 產生器生成式:(運算式 for 項目 in 可迭代項目)

注意到並沒有tuple生成式,上面的公式會回傳一種類型為generator的物件。這種產生器物件很特別,一旦被執行(例如用list()對它進行迭代)就無法再次使用。

函式(function)

1. 函式可以有任意數量及類型的參數(parameter),也可以回傳任意數量及類型的值,如果函式沒有使用return,呼叫函式之後會得到None:

>>> print(no_return())
None

None在Python中是一個特殊的值,它與False不一樣,雖然在布林運算中它屬於false。我們可以用is運算子來分辨遺漏值(missing value)與空值(empty value, 例如 ''、[]、(,)、{}、set())。

2. 函式的參數定義中可以有預設值,但是我們如果指定可變的值(串列、字典等)當作預設參數,該參數會被保留在函數的域(scope)當中,下一次呼叫該函式時,該預設參數的值會是上一次呼叫結束時的值。

3. 在函式呼叫時也有位置參數(照位置順序)及關鍵字參數(照參數定義)兩種方式。且位置參數及關鍵字參數可以混合使用。但是要注意混合使用時位置參數必須都在前面。

4. 用" * "來收集位置參數,例如foo(arg1, arg2, *args),args在此是tuple類型;用" ** "來收集關鍵字參數,例如bar(**kwargs),kwargs在此是dict類型。args和kwargs都是可隨意定義的參數名稱。

5. 文件字串是用來在函式定義的開頭加入一些說明用的,可以用'docstring'或'''docstring'''的方式加入,並使用help()來印出格式化的文件字串,echo.__doc__則是印出原始的文件字串。

閉包(Closure)

這其實就是一種內部函式,只要理解到所有函式本身所包含的區塊都是一個scope,在那個區塊當中的任何物件都認識彼此,因此當我們把這個內部函式用某種方式(例如當作回傳值)帶到更外部的scope時,我們就能把該scope的相關變數也帶過去。

>>> def foo(high):
             def inner():
                   return high
             return inner
>>> a = foo('Good')
>>> a()
'Good'
>>>type(a)
<class 'function'>

產生器(Generator)

產生器是一種序列(sequence)建立物件,可以用來迭代很大的序列,而不需在記憶體中儲存整個序列。通常產生器會是迭代器的資料來源。特別的是,每次迭代產生器時,它都會記得之前的呼叫(但其實類型還是一般的函式,除了把return改為yield之外並沒有什麼特殊的)中回傳的值到了哪裡。我們可以自己寫產生器函式:

>>> def giveMagicNumber(end):
               val = 1
               while val < end:
                       yield val * 9487
                       val++
>>> type(giveMagicNumber)
<class 'function'>
>>> a = giveMagicNumber(484)
>>> type(a)
<class 'generator'>

裝飾器(Decorator)

裝飾器可以拿來修飾原有的函式,例如加入除錯的log或是稍微在函式原有的執行流程上加入一些處理。我們可以直接呼叫裝飾器:


在以上的例子中,deco是裝飾器,add是原函式,可以看到在第10行我直接呼叫該裝飾器且加上參數,當然我們也可以先myNewFunc = deco(add)建立一個被裝飾過的函式後再呼叫也可以。Python中也可以直接把裝飾器加在函式定義上一行,告訴直譯器我們要直接裝飾原函式:

如果有多個裝飾器,會先執行最靠近函式的那個,再依序往上執行。







沒有留言:

張貼留言