Python學習手冊–第五部分(函數)
- 2020 年 2 月 14 日
- 筆記
在很多情況下,我們要實現功能需要編寫很多重複或者相似的程式碼,它們的運行步驟基本相同,只是某些數據可能存在差異。這個時候,為了避免反覆編寫相同的程式碼,我們可以使用一個函數來對某段程式碼塊進行封裝,而在需要該程式碼塊的地方,只需要調用函數即可。
定義函數
下面是一個非常簡單的函數:
def showText(): print('Hello!') showText()
這是一個最簡單的函數結構,第一行使用def關鍵字來告知Python,這是一個函數,然後showText用於指定你的函數名,名字任意,括弧內可以傳遞該函數所需的參數,因為僅僅是一個簡單的輸出語句,所以括弧里並沒有內容。最後,定義以冒號結尾。 要使用這個函數,我們只需要編寫showText()即可,運行程式輸出Hello!。
向函數傳遞資訊
上述的程式碼段並不友好,接下來我們進行一個簡單的改進:
def showText(name): print('Hello!' + name) showText('Jack')
只需稍作修改,就可以讓showText()函數不僅向用戶顯示Hello!,還將用戶的姓名用作抬頭,為此,我們在函數的括弧內添加name,表示在調用該函數的時候需要傳遞一個參數name,所以,我們在調用的時候,只需將用戶的姓名傳入,函數就會得到姓名並作相應的處理。
實參和形參
大多數程式語言中都有實參和形參的概念,在上述的程式段中,函數括弧內的name即是形參,而在調用該函數時傳入的『Jack』即是實參。
傳遞實參
了解了實參和形參的概念後,我們來了解一下如何向函數傳遞實參。 傳遞實參的方式很多,我們上面的例子使用的是位置實參,那麼什麼是位置實參?位置實參要求實參的順序與形參的順序相同。也就是說,形參的參數位置是怎樣的,你再傳遞實參的時候,參數位置也就應該是這樣,因為在位置實參中,實參和形參是一一對應的。
def showText(name, age): print(str(name) + '今年' + str(age) + "歲了") showText('Jack', 20)
上述程式段中,我們只需傳遞姓名和年齡,程式就會輸出Jack今年20歲了,但是,我們如果這樣編寫:
def showText(name, age): print(str(name) + '今年' + str(age) + "歲了") showText(20,'Jack')
這時候運行程式,輸出20今年Jack歲了,很明顯這樣就鬧笑話了。 所以,在使用位置實參方式時,千萬要注意形參的順序。
那麼第二種傳遞實參的方式就是關鍵字實參。它要傳遞給函數的名稱——值對,直接在實參中將名稱和值進行一一對應,因此以這種方式傳遞實參就不會混淆,關鍵字實參讓你無需考慮函數調用中的實參順序,還清楚地指出了函數調用中各個值的用途。
def showText(name, age): print(str(name) + '今年' + str(age) + "歲了") showText(age=20, name='Jack')
上述程式段中,即使我們將實參順序寫錯了,程式依然會輸出正確的結果。但是,在使用關鍵字實參時,務必準確指定函數定義中的形參名。
默認值
編寫函數時,可以給每個形參指定默認值,這樣當你在調用函數的時候,如果沒有傳遞實參,Python將會使用形參中的默認值進行處理。
def showText(name, age=20): print(str(name) + '今年' + str(age) + "歲了") showText('Jack')
上述程式段中,我們將age變數默認值指定為20,然後通過位置實參方式傳遞了Jack,程式運行正常。但是請注意,位置實參是嚴格要求實參位置的,所以如果你的形參name變數不是在第一位而是在第二位,程式就會報錯,因為按照位置實參的規則,你的Jack是傳遞到第一個形參變數。所以,要麼將name指定為第一個形參變數,要麼就是用關鍵字實參方式傳遞實參。
返回值
函數並非總是直接輸出,相反,它可以處理一些數據,並返回一個或一組值。函數返回的值被稱為返回值,在函數中,可以使用return語句將值返回到調用函數的程式碼行。 下面來看一個函數:
def dealName(first_name, last_name): full_name = first_name + ' ' + last_name return full_name.title() name = dealName('jimi', 'hendrix') print(name)
該程式段將傳遞過去的姓氏和名字進行一個簡單的拼接,並返回給調用者,進行輸出。
有時候,需要讓實參變成可選的,這樣使用函數的人就只需在必要時才提供額外的資訊。可使用默認值來讓實參變成可選的。
def dealName(first_name, middle_name, last_name): full_name = first_name + ' ' + middle_name + ' ' + last_name return full_name.title() name = dealName('john', 'lee', 'hooker') print(name)
例如這樣的一個程式段,當我們同時提供姓氏、名字和中間名時,程式正常運行。 然而並不是所有人都是有中間名的,但如果你只傳入姓氏和名字的話,顯然程式會報錯,那該怎麼辦呢?我們可以讓中間名變得可選,也就是給形參middle_name指定一個默認值——空字元串,並且在用戶沒有提供中間名的時候不使用這個形參。注意:我們需將形參middle_name移到參數末尾。
def dealName(first_name, last_name, middle_name=''): if middle_name: full_name = first_name + ' ' + middle_name + ' ' + last_name else: full_name = first_name + ' ' + last_name return full_name.title() name = dealName('john', 'hooker', 'lee') print(name)
在這個示例中,姓名是根據三個可能提供的部分創建的。由於人都有名和姓,因此在函數定義中首先列出了這兩個形參。中間名是可選的,因此在函數定義中最後列出該形參,並將其默認值設置為空字元串。 在函數體中,我們檢查是否提供了中間名。Python將非空字元串解讀為True ,因此如果函數調用中提供了中間名,if middle_name 將為True 。如果提供了中間名,就將名、中間名和姓合併為姓名,然後將其修改為首字母大寫格式,並返回到函數調用行。在函數調用行,將返回的值存儲在變數name 中;然後將這個變數的值列印出來。如果沒有提供中間名,middle_name 將為空字元串,導致if 測試未通過,進而執行else 程式碼塊:只使用名和姓來生成姓名,並將設置好格式的姓名返回給函數調用行。在函數調用行,將返回的值存儲在變數musician 中;然後將這個變數的值列印出來。
返回字典
函數可返回任何類型的值,包括列表和字典等複雜的數據類型。
def create_person(name, age): person = {'name': name, 'age': age} return person person = create_person('張三', 20) print(person)
上述程式段通過傳遞姓名和年齡從而構建出一個描述人資訊的字典並返回。
可將函數同之前的任何Python結構結合起來使用,例如:
def get_formatted_name(first_name, last_name): """返回整潔的姓名""" full_name = first_name + ' ' + last_name return full_name.title() # 這是一個無限循環! while True: print("n請輸入你的名字:") f_name = input("姓: ") l_name = input("名: ") formatted_name = get_formatted_name(f_name, l_name) print("nHello, " + formatted_name + "!")
上述程式段通過while循環結果函數的用法,以用戶輸入的姓名進行友好交互。
傳遞列表
很多時候,你會發現,向函數傳遞列表很有用。將列表傳遞給函數後,函數就能直接訪問其內容。 假設有一個用戶的列表,我們要問候其中的每位用戶:
def greet_users(users): for name in users: print('Hello!' + name.title()) users = ['張三', '李四', '王五'] greet_users(users)
輸出完全符合預期,每位用戶都看到了一條個性化的問候語。每當你要問候一組用戶時,都可調用這個函數。
在函數中修改列表
將列表傳遞給函數後,函數就可對其進行修改。在函數中對這個列表所做的任何操作都是永久性的。
def deal_list(fruits): fruits.pop() fruits = ['apple', 'banana', 'pear', 'orange'] deal_list(fruits) print(fruits)
禁止函數修改列表
有時候,需要禁止函數修改列表,這個時候,我們可以將列表的副本進行傳遞而不是傳遞原列表。
def deal_list(fruits): fruits.pop() return fruits fruits = ['apple', 'banana', 'pear', 'orange'] fruits_new = deal_list(fruits[:]) print(fruits) print(fruits_new)
傳遞任意數量的實參
有時候,你預先不知道函數需要接受多少個實參,好在Python允許函數從調用語句中收集任意數量的實參。 我們先來看一個例子:
def deal_hobby(*hobby): print(hobby) deal_hobby('足球', '籃球', '羽毛球', '乒乓球')
一個人的愛好是不確定數量的,所以在這裡,我們將函數的形參定義為*hobby,星號讓Python創建了一個名為hobby的空元組,並將接收到的值都封裝到這個元組中。
結合使用位置實參和任意數量實參
如果要讓函數接受不同類型的實參,必須在函數定義中將接納任意數量實參的形參放在最後。Python先匹配位置實參和關鍵字實參,再將餘下的實參都收集到最後一個形參中。 例如剛才的例子中,如果還需要一個表示姓名的形參,必須將該形參放在*hobby的前面。
def deal_hobby(name, *hobby): print(name + '的愛好:' + str(hobby)) deal_hobby('張三', '足球', '籃球', '乒乓球')
上述程式段中,第一個實參張三會去匹配形參name,其餘的三個實參都將存入形參hobby中。
使用任意數量的關鍵字實參
這個相信我不介紹你都會了吧,直接貼出示例程式碼。
def deal_hobby(name, **hobby): print(name + '的愛好:' + str(hobby)) deal_hobby(name='張三', ball='籃球', sport=' 跑步')
將函數存儲在模組中
函數的優點之一是,使用它們可將程式碼塊與主程式分離。通過給函數指定描述性名稱,可讓主程式容易理解得多。你還可以更進一步,將函數存儲在被稱為模組 的獨立文件中,再將模組導入 到主程式中。import 語句允許在當前運行的程式文件中使用模組中的程式碼。通過將函數存儲在獨立的文件中,可隱藏程式程式碼的細節,將重點放在程式的高層邏輯上。這還能讓你在眾多不同的程式中重用函數。將函數存儲在獨立文件中後,可與其他程式設計師共享這些文件而不是整個程式。知道如何導入函數還能讓你使用其他程式設計師編寫的函數庫。 導入模組的方法有多種,下面對每種都作簡要的介紹。 要讓函數是可導入的,得先創建模組。模組 是擴展名為.py的文件,包含要導入到程式中的程式碼。 先創建demo9.py文件。
def sum(numbers): sum = 0 for number in numbers: sum += number return sum
再創建demo10.py,通過import導入demo9模組。
import demo9; numbers = (1, 2, 3, 4, 5, 6, 7, 8, 9) sum = demo9.sum(numbers) print(sum)
這樣就能調用模組中的函數,從而計算出1~9之和。
導入特定的函數
你還可以導入模組中的特定函數,這種導入方法的語法如下:
from demo9 import sum numbers = (1, 2, 3, 4, 5, 6, 7, 8, 9) sum = sum(numbers) print(sum)
在sum後面還可以跟上任意數量的函數名,中間用逗號分隔。 若使用這種語法,調用函數時就無需使用句點。由於我們在import 語句中顯式地導入了函數sum() ,因此調用它時只需指定其名稱。
使用as給函數指定別名
如果要導入的函數的名稱可能與程式中現有的名稱衝突,或者函數的名稱太長,可指定簡短而獨一無二的別名 ——函數的另一個名稱,類似於外號。要給函數指定這種特殊外號,需要在導入它時這樣做。
from demo9 import sum as s; numbers = (1, 2, 3, 4, 5, 6, 7, 8, 9) sum = s(numbers) print(sum)
上述程式段中,我們對demo9模組中的sum()函數起了一個別名s,這樣我們在使用該函數的時候只需要寫成s()即可。
使用as給模組指定別名
你還可以給模組指定別名。通過給模組指定簡短的別名(如給模組pizza 指定別名p ),讓你能夠更輕鬆地調用模組中的函數。
import demo9 as d numbers = (1, 2, 3, 4, 5, 6, 7, 8, 9) sum = d.sum(numbers) print(sum)
這樣我們就能夠通過別名d來調用模組中的函數了。
導入模組中的所有函數
如果想一次性導入模組中的所有函數,你可以這麼做。
from demo9 import * print(sum((1, 2, 3, 4, 5)))
使用星號可以讓Python將模組中的所有函數進行導入,由於導入了每個函數,可通過名稱來調用每個函數,而無需使用句點表示法。然而,使用並非自己編寫的大型模組時,最好不要採用這種導入方法:如果模組中有函數的名稱與你的項目中使用的名稱相同,可能導致意想不到的結果:Python可能遇到多個名稱相同的函數或變數,進而覆蓋函數,而不是分別導入所有的函數。最佳的做法是,要麼只導入你需要使用的函數,要麼導入整個模組並使用句點表示法。這能讓程式碼更清晰,更容易閱讀和理解。這裡之所以介紹這種導入方法,只是想讓你在閱讀別人編寫的程式碼時,如果遇到類似情況,能夠理解它們。