2024年6月16日 Python - 函式

流星<。)#)))≦發表於2024-06-17

函式

函式是組織好的,可重複使用的,用來實現單一,或相關聯功能的程式碼段。

Python 提供了許多內建函式,比如 print() 。但你也可以自己建立函式,這被叫做使用者自定義函式。

定義一個函式

定義一個函式,以下是簡單的規則:

  • 函式程式碼塊以 def 關鍵詞開頭,後接函式識別符號名稱和圓括號 ()
  • 任何傳入引數和自變數必須放在圓括號中間,圓括號之間可以用於定義引數
  • 函式的第一行語句可以選擇性地使用文件字串:用於存放函式說明
  • 函式內容以冒號 : 起始,並且縮排
  • return [表示式] 結束函式,選擇性地返回一個值給呼叫方,不帶表示式的 return 相當於返回 None

img

語法

Python 定義函式使用 def 關鍵字,一般格式如下:

def 函式名(引數列表):
    函式體

預設情況下,引數值和引數名稱是按函式宣告中定義的順序匹配起來的。

例項

使用函式來輸出"Hello World!":

#!/usr/bin/python3

def hello():
    print("Hello World!")


hello()
hello()

函式中帶上引數變數:

#!/usr/bin/python3

def max(a, b):
    if a > b:
        return a
    else:
        return b


a = 4
b = 5
print(max(a, b))

函式呼叫

定義一個函式:給了函式一個名稱,指定了函式里包含的引數,和程式碼塊結構。

這個函式的基本結構完成以後,你可以透過另一個函式呼叫執行,也可以直接從 Python 命令提示符執行。

#!/usr/bin/python3

# 定義函式
def printme(str):
    # 列印任何傳入的字串
    print(str)
    return


# 呼叫函式
printme("我要呼叫使用者自定義函式!")
printme("再次呼叫同一函式")

引數傳遞

在 python 中,型別屬於物件,物件有不同型別的區分,變數是沒有型別的:

a=[1,2,3]

a="Runoob"

變數 a 是沒有型別,它僅僅是一個物件的引用(一個指標),可以是指向 List 型別物件,也可以是指向 String 型別物件

可更改(mutable)與不可更改(immutable)物件

在 python 中,strings, tuples 和 numbers 是不可更改的物件,而 list, dict 等則是可以修改的物件。

  • 不可變型別:變數賦值 a=5 後再賦值 a=10,這裡實際是新生成一個 int 值物件 10,再讓 a 指向它,而 5 被丟棄,不是改變 a 的值,相當於新生成了 a
  • 可變型別:變數賦值 la=[1,2,3,4] 後再賦值 la[2]=5 則是將 list la 的第三個元素值更改,本身la沒有動,只是其內部的一部分值被修改了

python 函式的引數傳遞:

  • 不可變型別:類似 C++ 的值傳遞,如整數、字串、元組。如 fun(a) ,傳遞的只是 a 的值,沒有影響 a 物件本身。如果在 fun(a) 內部修改 a 的值,則是新生成一個 a 的物件
  • 可變型別:類似 C++ 的引用傳遞,如 列表,字典。如 fun(la) ,則是將 la 真正的傳過去,修改後 fun 外部的 la 也會受影響

python 中一切都是物件,嚴格意義我們不能說值傳遞還是引用傳遞,我們應該說傳不可變物件和傳可變物件。

傳不可變物件例項

透過 id() 函式來檢視記憶體地址變化:

def change(a):
    print(1, id(a))  # 指向的是同一個物件
    a = 10
    print(2, id(a))  # 一個新物件


a = 1
print(0, id(a))
change(a)
print(3, id(a))

輸出結果為:

0 2682404864240
1 2682404864240
2 2682404864528
3 2682404864240

傳可變物件例項

#!/usr/bin/python3

# 可寫函式說明
def changeme(mylist):
    "修改傳入的列表"
    mylist.append([1, 2, 3, 4])
    print("函式內取值: ", mylist)
    return


# 呼叫changeme函式
mylist = [10, 20, 30]
changeme(mylist)
print("函式外取值: ", mylist)

輸出結果如下:

函式內取值:  [10, 20, 30, [1, 2, 3, 4]]
函式外取值:  [10, 20, 30, [1, 2, 3, 4]]

引數

以下是呼叫函式時可使用的正式引數型別:

  • 必需引數
  • 關鍵字引數
  • 預設引數
  • 不定長引數

必需引數

必需引數須以正確的順序傳入函式。呼叫時的數量必須和宣告時的一樣。

關鍵字引數

關鍵字引數和函式呼叫關係緊密,函式呼叫使用關鍵字引數來確定傳入的引數值。

使用關鍵字引數允許函式呼叫時引數的順序與宣告時不一致,因為 Python 直譯器能夠用引數名匹配引數值。

函式引數的使用不需要使用指定順序:

#!/usr/bin/python3

# 可寫函式說明
def printinfo(name, age):
    "列印任何傳入的字串"
    print("名字: ", name)
    print("年齡: ", age)
    return


# 呼叫printinfo函式
printinfo(age=50, name="runoob")

預設引數

呼叫函式時,如果沒有傳遞引數,則會使用預設引數。

#!/usr/bin/python3

# 可寫函式說明
def printinfo(name, age=35):
    "列印任何傳入的字串"
    print("名字: ", name)
    print("年齡: ", age)
    return


# 呼叫printinfo函式
printinfo(age=50, name="runoob")
print("------------------------")
printinfo(name="runoob")

輸出結果:

名字:  runoob
年齡:  50
------------------------
名字:  runoob
年齡:  35

不定長引數

基本語法如下:

def functionname([formal_args,] *var_args_tuple ):
   "函式_文件字串"
   function_suite
   return [expression]

加了星號 * 的引數會以元組(tuple) 的形式匯入,存放所有未命名的變數引數。

#!/usr/bin/python3

# 可寫函式說明
def printinfo(arg1, *vartuple):
    "列印任何傳入的引數"
    print("輸出: ")
    print(arg1)
    print(vartuple)


# 呼叫 printinfo 函式
printinfo(70, 60, 50)

輸出結果:

輸出: 
70
(60, 50)

如果在函式呼叫時沒有指定引數,它就是一個空元組。

我們也可以不向函式傳遞未命名的變數。

#!/usr/bin/python3

# 可寫函式說明
def printinfo(arg1, *vartuple):
    "列印任何傳入的引數"
    print("輸出: ")
    print(arg1)
    print(vartuple)
    for var in vartuple:
        print(var)
    return


# 呼叫printinfo 函式
printinfo(10)


輸出結果:

輸出: 
10
()

還有一種就是引數帶兩個星號 ** 基本語法如下:

def functionname([formal_args,] **var_args_dict ):
   "函式_文件字串"
   function_suite
   return [expression]

加了兩個星號 ** 的引數會以字典的形式匯入。

#!/usr/bin/python3

# 可寫函式說明
def printinfo(arg1, **vardict):
    "列印任何傳入的引數"
    print("輸出: ")
    print(arg1)
    print(vardict)


# 呼叫printinfo 函式
printinfo(1, a=2, b=3)

輸出結果:

輸出: 
1
{'a': 2, 'b': 3}

宣告函式時,引數中星號 * 可以單獨出現,例如:

def f(a,b,*,c):
    return a+b+c

如果單獨出現星號 * 後的引數必須用關鍵字傳入。

def f(a, b, *, c):
    return a + b + c


# f(1, 2, 3)      # TypeError: f() takes 2 positional arguments but 3 were given
f(1, 2, c=3)        # 正常

匿名函式

Python 使用 lambda 來建立匿名函式。

所謂匿名,意即不再使用 def 語句這樣標準的形式定義一個函式。

  • lambda 只是一個表示式,函式體比 def 簡單很多
  • lambda 的主體是一個表示式,而不是一個程式碼塊。僅僅能在 lambda 表示式中封裝有限的邏輯進去
  • lambda 函式擁有自己的名稱空間,且不能訪問自己引數列表之外或全域性名稱空間裡的引數
  • 雖然 lambda 函式看起來只能寫一行,卻不等同於 C 或 C++ 的行內函數,後者的目的是呼叫小函式時不佔用棧記憶體從而增加執行效率

語法

lambda 函式的語法只包含一個語句,如下:

lambda [arg1 [,arg2,.....argn]]:expression

設定引數 a 加上 10 :

x = lambda a: a + 10
print(x(5))  # 15

以下例項匿名函式設定兩個引數:

#!/usr/bin/python3

# 可寫函式說明
sum = lambda arg1, arg2: arg1 + arg2

# 呼叫sum函式
print("相加後的值為 : ", sum(10, 20))  # 30
print("相加後的值為 : ", sum(20, 20))  # 40

我們可以將匿名函式封裝在一個函式內,這樣可以使用同樣的程式碼來建立多個匿名函式。

以下例項將匿名函式封裝在 myfunc 函式中,透過傳入不同的引數來建立不同的匿名函式:

def myfunc(n):
    return lambda a: a * n


mydoubler = myfunc(2)
mytripler = myfunc(3)

print(mydoubler(11))    # 22
print(mytripler(11))    # 33

return 語句

return [表示式] 語句用於退出函式,選擇性地向呼叫方返回一個表示式。不帶引數值的 return 語句返回 None

強制位置引數

Python3.8 新增了一個函式形參語法 / 用來指明函式形參必須使用指定位置引數,不能使用關鍵字引數的形式。

在以下的例子中,形參 a 和 b 必須使用指定位置引數,c 或 d 可以是位置形參或關鍵字形參,而 e 和 f 要求為關鍵字形參:

def f(a, b, /, c, d, *, e, f):
    print(a, b, c, d, e, f)

以下使用方法是正確的:

f(10, 20, 30, d=40, e=50, f=60)

以下使用方法會發生錯誤:

f(10, b=20, c=30, d=40, e=50, f=60)   # b 不能使用關鍵字引數的形式
f(10, 20, 30, 40, 50, f=60)           # e 必須使用關鍵字引數的形式

相關文章