iT邦幫忙

2023 iThome 鐵人賽

DAY 15
0
Software Development

跟著 OXXO 一起學 Python系列 第 30

( Day 15.1 ) Python 函式 function

  • 分享至 

  • xImage
  •  

當程式越來越複雜的時候,就必須將一些重複或有特別定義的程式,拆分成容易管理的小程式,這些小程式就稱為「函式」,函式是一種有名稱且獨立的程式片段,可以接收任何型態的參數,處理完成後也可以輸出任何型態的結果。

原文參考:函式 function

本篇使用的 Python 版本為 3.7.12,所有範例可使用 Google Colab 實作,不用安裝任何軟體 ( 參考:使用 Google Colab )

定義函式

在 Python 裡,使用「def」定義一個函式,函式的命名規則和變數相同 ( 只能以字母或底線開頭,內容只能使用字母、數字或底線 ),下方程式碼是一個名為 hello 函式的基本架構:

def 後方通常會放上函式名稱 ( 名稱不能和變數名稱重複 )、輸入參數的小括號,後方再加上一個冒號,函式的程式採用「縮排」的方式表現 ( 參考:縮排 )。

def hello():
    print('hello')
hello()    # 執行函式,印出 hello

注意,一定要「先定義函式,再執行函式」,不然執行時會發生錯誤,下方的程式將執行函式放在定義函式之前,執行時就會發生錯誤。

hello()
def hello():
    print('hello')   # 發生錯誤 name 'hello' is not defined

函式參數

函式可以加入「參數」,執行函式時給予這些參數指定的數值 ( 引數 ),就能讓函式根據不同參數的內容,計算出不同的結果

下方的 hello 函式有一個 msg 參數,執行函式時如果給予的內容不同,就會呈現不同的結果。

def hello(msg):
    print(msg)

hello('hello')        # hello
hello('good morning') # good morning

一個函式可以放入「多個」參數,下方的 hello 函式具有 x 和 y 兩個參數,根據不同的參數數值進行計算,最後呈現不同數值的加總結果。

注意,執行函式時,會按照「順序」處理多個參數,例如函式參數順序如果是 (x,y),執行時填入 (1,2),x 就會是 1,y 就會是 2。

def hello(x,y):
    z = x + y
    print(z)

hello(1,2)    # 3
hello(5,6)    # 11

參數預設值

函式的參數可以「指定預設值」,如果執行函式時沒有提供參數數值,參數就會自動帶入預設值執行,下方的程式設定參數 y 的預設值為 10,如果執行時沒有提供參數 y 數值,y 就會使用 10 帶入計算。

def hello(x,y=10):
    z = x + y
    print(z)

hello(1,2)    # 3
hello(5)      # 15

關鍵字引數

函式除了透過「順序」( 位置 ) 指定參數外,也可以使用「關鍵字引數」( 指定的名稱 ) 來設定特定的參數內容 ( 引數表示提供給參數的數值 )。

下方的程式裡,hello 函式有 name 和 age 兩個參數,如果執行函式時提供的數值順序不同,產生的結果就會不同,如果額外使用關鍵字引數,就算提供的內容順序不同,仍然會是正確的結果

def hello(name, age):
    msg = f'{name} is {age} years old'
    print(msg)

hello('oxxo',18)     # oxxo is 18 years old
hello(18,'oxxo')     # 18 is oxxo years old ( 因為 18 和 oxxo 對調,所以結果就會對調 )
hello(age=18,name='oxxo')   # oxxo is 18 years old ( 使用關鍵字引數,結果就會是正確的 )

此外,在定義函式時也可以賦予關鍵字引數內容,執行後就算沒有提供該引數的數值,仍然會套用預設值,以下方的程式為例,如果不指定 start 和 end,就會預設使用 0 和 3。

def test(a, start=0, end=3):
    for i in a[start:end]:
        print(i)

b = [1,2,3,4,5]
test(b, start=2, end=len(b))  # 3 4 5
test(b)             # 1 2 3

函式回傳值

函式除了可以傳入參數,也可以使用「return」回傳程式運算後的結果,回傳的結果不限型態,可以是數字、字串、串列、tuple...等,下方的程式碼,執行函式 a 之後,函式會計算並回傳 x + y x 2 的結果,最後將結果賦值給變數 b 和 c。

def a(x, y):
    result = x + y*2
    return result

b = a(1,2)
c = a(2,3)
print(b)   # 5
print(c)   # 8

當函式執行的過程中遇到 return 時,就會「中止函式」並將結果回傳,以下方的程式為例,當 x=1 ( 每次 result 增加 1 ) 的時候,會觸發 result==5 的邏輯判斷,就會中止函式 ( 函式內的 while 迴圈也就跟著停止 ),並回傳 5 的結果,當 x=2 ( 每次 result 增加 2 ) 的時候,不會處發 result==5 的邏輯判斷,就會執行完 while 迴圈,最後回傳 10 的結果。

def a(x):
    result = 0
    while result < 10:
        result = result + x
        if result==5:
            return result
    return result

b = a(1)
c = a(2)
print(b)   # 5
print(c)   # 10

函式也可以回傳多個結果,如果回傳多個結果,可以賦值給「同樣數量」的變數 ( 不同數量會發生錯誤 )。

def test(x, y, z):
    return x+1, y+1, z+1

a, b, c = test(1, 2, 3)    # 賦值給「同樣數量」的變數
print(a)    # 2
print(b)    # 3
print(c)    # 4

函式回傳的多個結果也可以只賦值給一個變數,這時就會將多個結果變成一個 tuple

def test(x, y, z):
    return x+1, y+1, z+1

a = test(1, 2, 3)
print(a)    # (2, 3, 4)

函式內的函式

在一個函式裡也可以放入另外的函式,形成函式內的函式 ( 某些情況下會成為「閉包」 ),但函式內的函式只能在函式裡使用,下方的程式碼,在 hello 函式裡,建立了 h1 和 h2 的內部函式,根據不同的參數執行不同的函式,如果在外部執行內部函式,就會發生錯誤。

def hello(n, msg):
    def h1():       # 內部函式
        return msg
    def h2():       # 內部函式
        return msg*2
    if n == 1:
        print(h1())
    if n == 2:
        print(h2())
hello(1, 'ok')   # ok
hello(2, 'ok')   # okok
print(h2())      # 發生錯誤 name 'h2' is not defined

函式內的變數

如果放在函式裡的變數,沒有經過 global 的宣告,就會成為「區域變數」( 更多參考:全域變數、區域變數 )。

a = 123           # 全域變數 a
b = 123           # 全域變數 b
def hello(msg):
    a = msg         # 區域變數 a,更動區域變數不影響全域變數
    print(a)
    global b        # 宣告變數 b 是使用全域變數 b,更動變等同更動全域變數
    b = msg
hello(456)        # 456
print(a)          # 123
print(b)          # 456 被更改為 456

如果函式裡又有其他函式,需要使用區域變數,可以將變數宣告為 nonlocal 的自由變數,就能自由地在函式裡使用,下方的程式碼有宣告 a 為自由變數,所以執行後會正常運作,但因為 b 沒有宣告為自由變數,所以使用時就會發生錯誤 ( 更多參考:自由變數 nonlocal )。

def hello(msg):
    a = 123
    b = 123
    def h1():
        nonlocal a    # 宣告 a 為自由變數
        a = a + msg
        print(a)
    def h2():
        b = b + msg
        print(b)
    h1()            # 579
    h2()            # 發生錯誤  local variable 'b' referenced before assignment
hello(456)

*args、**kwargs 運算子

如果把函式的參數設定帶有 args ( 一個星號 * ) 運算子的參數,則傳入的所有參數,都會被組合成 tuple 的型態,下方的函式使用了「*args」的參數,執行函式時不論給予多少引數,最後都會組合成 tuple。

args 和 kwargs 的英文名稱只是「變數名稱」,可以自由更換,重點在於前方的一個星號與兩個星號

def test(*args):
    print(args)

test(1,2,3,'a','b','c')

# (1,2,3,'a','b','c')

如果把函式的參數設定帶有 kwargs ( 兩個星號 ** ) 運算子的參數,則傳入的所有「帶有關鍵字引數」的參數,都會被組合成字典的型態,下方的函式使用了「**kwargs」的參數,執行函式時不論給予多少引數,最後都會組合成字典。

def test(**kwargs):
    print(kwargs)

test(name='oxxo',age=18,like='book')

 # {'name': 'oxxo', 'age': 18, 'like': 'book'}

如果 *args**kwargs 同時出現,則會根據輸入的內容,分別套用 *args*kwargs,下方的 a 函式在執行時,傳入不同的參數,最後呈現的結果就會按照參數型態的不同而有所區隔。

def a(*args, **kwargs):
    print(args)
    print(kwargs)

a([123, 456], x=1, y=2, z=3)

# ([123, 456],)
# {'x': 1, 'y': 2, 'z': 3}

同理,如果將一個星號套用在 print() 裡 ( print() 算是一個內建函式 ),就會將可迭代的物件打散後印出。

a = [1,2,3,4,5]
b = (1,2,3,4,5)
c = {'x':1,'y':2,'z':3}
d = {'x','y','z'}

print(*a)   # 1 2 3 4 5
print(*b)   # 1 2 3 4 5
print(*c)   # x y z
print(*d)   # x y z

使用 pass

如果想定義一個什麼事都不做的空函式,可以使用 pass 語句:

def test():
    pass

pass 除了可以應用在函式,也可以使用在判斷式裡,作為一個佔位符使用 ( 不會執行任何事情,但必須出現的程式碼 )。

a = int(input('>'))
if a>10:
    pass       # 如果輸入的數字大於 10,不做任何事情
else:
    print(a)

更多教學

大家好,我是 OXXO,是個即將邁入中年的斜槓青年,我有個超過一千篇教學的 STEAM 教育學習網,有興趣可以參考下方連結呦~ ^_^


上一篇
( Day 14.2 ) Python 匯入模組 import
下一篇
( Day 15.2 ) Python 匿名函式 lambda
系列文
跟著 OXXO 一起學 Python101
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言