Python Deep Drive I 第五節 Function Parameters 筆記

分享我自己這一章節的筆記,因為是照自己習慣寫給我自己看的,所以難免囉嗦冗長,還請大家多多見諒,以下是筆記連結: (5). Python Deep Drive I : 第五節 Function Parameters

感謝 Chris 兄不吝分享,以下為 Sky 代為整理。


Introduction

這一節老師要介紹的是函式(Function),以下是這一節關於函式要講解的範圍~


Argument vs Parameter

函式中"定義"需要傳入做運算的變數叫做參數 (parameters),而在函式外,宣告要用來作為傳入到函式做運算的叫做引數(Arguments)。

當函式引用了變數作為引數時,函式的參數和使用的引數都是指向同一個參考(記憶位址)~


Positional and Keyword Arguments

函式中引數的位置是有固定的順序位置,比方說,如下圖,若函式宣告的參數順序是先 a 再 b,那如果有兩個變數 x, y 其中 x = 10, y = 20,當 x, y 要放入函式中執行,且其中對應關係 x -a, y -b,那函式的執行要寫成 my_func(10, 20),而當 a, b 順序要對調時,必須要把參數對應 明確表示 出來,寫成 my_func(b=20, a=10)

放入函式的 {\color{red} {參數,可設定預設值}} (當引數帶入到函式中時,如沒包含到這個參數時,則有設定預設值的參數會引用預設值作為當下函式被呼叫時的引數使用),而有預設值的參數必須放在所有無預設值設定參數的最後面:

正確寫法: def my_func(a, b, c = 100)

錯誤寫法: def my_func(a = 100, b, c) or def my_func(a, b = 100, c)

正確寫法: def my_func(a, b = 100, c = 100)

[Note]: {\color{red} {有預設值的參數要往後擺,沒有預設值的參數要在有預設值參數的前面}} ,這樣如果一個函式有三個參數,例如:

my_func(a, b = 50, c = 100),那如果我要放入一個引數進去,就可以寫成 my_func(10)

表示 my_func(10, 50, 100) 其中 50 是 b 的預設值,而 100 則是 c 的預設值;

或是我要放入兩個引數,如 my_func(10, 20)

表示 my_func(10, 20, 100) 其中 20 是 b 的新設定值,而 c 因為沒有引數對應,就會使用預設值 100 作為 c 的設定值。

如果帶入引數的順序與指派參數的位置對應完全一致,則可省略在帶入引數時對參數對應的明確宣告,比方說:

def my_func(a, b, c):

如有三個變數 x = 10, y = 20, z = 30, 其中 x -a, y -b, z -c,則 my_func(a = 10, b = 20, c = 30) 可簡化寫成 my_func(10, 20, 30) 即可。

但同樣的,如果多參數的函式,其中 {\color{red} {參數的安排順序有變,則必須明確表示}}

def my_func(a, b=2, c=3)

my_func(10, 20, 30) 

my_func(a = 10, c = 30, b = 20) 

my_func(c = 30, a = 10, b = 20)

範例摘錄說明:

Positional Arguments

# Positional Arguments
def my_func(a, b, c):
    print("a={0}, b={1}, c={2}".format(a, b, c))

my_func(1, 2, 3)
a=1, b=2, c=3

Default Values

# Default Values
def my_func(a, b=2, c=3):
    print("a={0}, b={1}, c={2}".format(a, b, c))

# Note that once a parameter is assigned a default value, 
# all parameters thereafter must be asigned a default value too!

# For example, this will not work:
def fn(a, b=2, c):
    print(a, b, c)

SyntaxError: non-default argument follows default argument
def my_func(a, b=2, c=3):
    print("a={0}, b={1}, c={2}".format(a, b, c))

my_func(10, 20, 30)
a=10, b=20, c=30
my_func(10, 20)
a=10, b=20, c=3
my_func(10)
a=10, b=2, c=3
# Since a does not have a default value, it must be specified:
my_func()
TypeError: my_func() missing 1 required positional argument: 'a'

Keyword Arguments (named arguments)

# Keyword Arguments (named arguments)

# Positional arguments, can optionally, be specified using their corresponding parameter name.
# This allows us to pass the arguments without using the positional assignment:

def my_func(a, b=2, c=3):
    print("a={0}, b={1}, c={2}".format(a, b, c))

my_func(c=30, b=20, a=10)
a=10, b=20, c=30
my_func(10, c=30, b=20)
a=10, b=20, c=30
# Note that once a keyword argument has been used, 
# all arguments thereafter must also be named:
my_func(10, b=20, 30)
SyntaxError: positional argument follows keyword argument
# However, if a parameter has a default value, 
# it can be omitted from the argument list, named or not:
my_func(10, c=30)
a=10, b=2, c=30
my_func(a=30, c=10)
a=30, b=2, c=10
my_func(c=10, a=30)
a=30, b=2, c=10

Unpacking Iterables

封裝 Packing、解封裝 Unpacking 及 遞迴性 Iterable

此節專題觀看前的預習資料:

其實這邊要穿插解說一下什麼是 iterable、iterator 以及 generator 的差別,這將有助於對後面老師所談到的跟迭代(iteration)有關的概念的理解。

知識點來源:

Python中的iterable、iterator和generator(一)

Python中的iterable、iterator和generator(二)

iterable 顯然是一種可以迭代的東西,既然如此,那麼 {\color{red} {str、list、tuple、set、dict 等預設的 Python objects 都是 iterable}} ,都可以將它們用 for 語句做迭代:

names = ['Mary', 'Jack', 'Emily', 'Lauren', 'Olivia']
for name in names:
	print(name)
Mary
Jack
Emily
Lauren
Olivia

那iterable可以產生iterator又是甚麼意思呢?用dir函數看看list這個iterable有甚麼方法可以調用:

dir(names)
['__add__', '__class__', '__contains__', '__delattr__', '__delitem__',
'__dir__', '__doc__', '__eq__', '__format__', '__ge__',
'__getattribute__', '__getitem__', '__gt__', '__hash__', '__iadd__',
'__imul__', '__init__', '__init_subclass__', '__iter__', '__le__',
'__len__', '__lt__', '__mul__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__reversed__', '__rmul__',
'__setattr__', '__setitem__', '__sizeof__', '__str__', '__subclasshook__',
'append', 'clear', 'copy', 'count', 'extend',
'index', 'insert', 'pop', 'remove', 'reverse', 'sort']

使用 dir 查看 name 這個 list 還包含哪些內建方法屬性,我們會發現 names 這個 list 中有一個叫 __iter__ 的方法,而 iterable 就是透過這個方法來產生一個 iterator。Python已內建了 iter 函式讓我們調用 iterable object 中的 __iter__ 方法,不用寫為 names.__iter__() 的樣子:

iter(names)
<list_iterator object at 0x03085190>

iterator 和 iterable 最大的分別是 iterator 有一個叫 __next__ 的方法,這個方法可以返回序列中的下一個內容。由於 Python 也內建了 next 函數調用 object 中的 __next__ 方法,所以不用寫為 names_iter.__next__(),每調用一次 __next__ 方法,序列中的內容就會被讀出一個,直到讀完所有內容。

next(names_iter)
'Mary'
next(names_iter)
'Jack'
next(names_iter)
'Emily'

iterable 是沒有__next__方法的,你不能用next來從iterable中將序列內容讀出:

next(names)
Traceback (most recent call last):
    File "<stdin>", line 1, in <module>
TypeError: 'list' object is not an iterator

小結一下

  • iterable 中有 __iter__ 方法,調用它會產生一個對應的 iterator。

  • iterator 中有 __next__ 方法,調用它會返回對應 iterable 序列中的內容。

  • iterator 中也有 __iter__ 方法,調用它會返回自己,由於 iterator 有 iterable 中的 __iter__ 方法,所以說 iterator 也是 iterable 的。

  • iterator 有 __iter__ 方法的原因是方便我們直接用 iterator 進行迭代操作。

  • {\color{red} {每個 iterator 只能迭代一次,要重新迭代,就要從 iterable 重新製造一個新的 iterator。}}

  • 不同 iterator 做迭代時各自獨立工作,所以可對同一個 iterable 做多重迭代,因為 Python 會在同不同層次的迭代中用iterable 製作一個新的 iterator。

延伸閱讀:

一文徹底搞懂Python(Iterable)、(Iterator)和(Generator)的概念


  • tuple 有無小括號都可以,例如: x = (1, 2, 3) 可直接寫成 x = 1, 2, 3。加上小括號,只是讓 tuple 的宣告更明確

  • 如果 tuple 只有一個成員,如下圖,必須寫成 (1,) 或是 1,

  • 當只有一個成員時,不可以寫成 (1) => 只是整數加上表示優先處理的小括號,並非 tuple,要宣告成 tuple 必須加上逗號 , 符號。

  • 唯一例外的是空集合: () 或 tuple()

  • 不同的集合使用不同的符號: {\color{red} {() 表 tuple;[] 表 list;{} 表 set;{'a' : 1, 'b' : 2} 表 dictionary}}

  • 當不同集合放在一起時,就必須加上符號以明確表示~

  • {\color{red} {字串本身其實是字元的 tuple 集合,因此字串本身是視為字元的 tuple 集合~}}

  • {\color{red} {但凡變數有遞迴屬性(iterable)的就可視為是一個封裝(集合)變數}}

  • Unpacking => (集合)解封裝,就是將變數指向(對應)集合的成員,直接看下圖老師的圖解說明比較清楚,例如 a, b, c = [1, 2, 3] 表示 a => 1, b => 2, c => 3

  • Note: 引數的順序會直接默認對應集合成員的順序

  • {\color{red} { 使用 for 在集合上,會遞迴返回每個集合成員~}}

  • 如引數的對應需要改變順序,在 Python,可直接變更(swap),不需指定額外變數(如下圖的 tmp)來暫存~

  • {\color{red} {對 dictionary 字典集合,使用 for 只會返回所有字典成員的 key 值}}

  • {\color{red} {dictionary 和 set 在 for 取值(return) 部分是無排序性的(並非會依照 index 返回成員),這一點必須小心}} ,如下圖中之範例:

範例摘錄說明:

正確與錯誤的 assign tuple class:

(未完,待續…)

  1. Extended Unpacking - Lecture
  2. Extended Unpacking - Coding
  3. *args - Lecture
  4. *args - Coding
  5. Keyword Arguments - Lecture
  6. Keyword Arguments - Coding
  7. **kwargs
  8. Putting it all Together - Lecture
  9. Putting it all Together - Coding
  10. Application: A Simple Function Timer
  11. Parameter Defaults - Beware!!
  12. Parameter Defaults - Beware Again!!
2個讚

謝謝 sky 兄,我突然發現,因為我有時在辦公室電腦抽空看教學記筆記,有時是在家裡的筆電做的,而 evernote 有時秀逗了,竟然把一樣的檔案竟然因此分開成兩個,而第五節的筆記正好又遇上這樣問題,我把舊的重複的刪掉,但發現刪掉的竟然是共用的,因此這一篇我重新再分享一次: (5). Python Deep Drive I : 第五節 Function Parameters
[註]: 我發現 sky 兄幫我整理的,好像有少了一些內容,不知道是不是那時分享的那篇重複彼既是不是內容有少,不論如何,請改以這篇分享為準~

3個讚

沒問題,多謝說明。

這週比較忙,等忙完後我再繼續更新。

我原本打算一併更新原始發文的連結,但發現連結依然有效,所以暫不更動。請參考,再次感謝!

2個讚