從零開始學Python:第八課-函式和模組
在講解本章節的內容之前,我們先來研究一道數學題,請說出下面的方程有多少組正整數解。
你可能已經想到了,這個問題其實等同於將8個蘋果分成四組且每組至少一個蘋果有多少種方案,因此該問題還可以進一步等價於在分隔8個蘋果的7個空隙之間插入三個隔板將蘋果分成四組有多少種方案,也就是從7個空隙選出3個空隙放入隔板的組合數,所以答案是
組合數的計算公式如下所示:
根據我們前面學習的知識,可以用迴圈做累乘來計算階乘,那麼透過下面的Python程式碼我們就可以計算出組合數
的值,程式碼如下所示:
"""
輸入M和N計算C(M,N)
Version: 0.1
Author: 駱昊
"""
m = int(input(
'm = '))
n = int(input(
'n = '))
# 計算m的階乘
fm = 1
for num in range(1, m + 1):
fm *= num
# 計算n的階乘
fn = 1
for num in range(1, n + 1):
fn *= num
# 計算m-n的階乘
fm_n = 1
for num in range(1, m - n + 1):
fm_n *= num
# 計算C(M,N)的值
print(fm // fn // fm_n)
函式的作用
不知大家是否注意到,上面的程式碼中我們做了三次求階乘,雖然m、n、m - n的值各不相同,但是三段程式碼並沒有實質性的區別,屬於重複程式碼。世界級的程式設計大師Martin Fowler先生曾經說過:“ 程式碼有很多種壞味道,重複是最壞的一種!”。要寫出高質量的程式碼首先要解決的就是重複程式碼的問題。對於上面的程式碼來說,我們可以將計算階乘的功能封裝到一個稱為“函式”的程式碼塊中,在需要計算階乘的地方,我們只需要“呼叫函式”就可以了。
定義函式
在Python中可以使用def關鍵字來定義函式,和變數一樣每個函式也應該有一個漂亮的名字,命名規則跟變數的命名規則是一致的。在函式名後面的圓括號中可以放置傳遞給函式的引數,就是我們剛才說到的函式的自變數,而函式執行完成後我們會透過return關鍵字來返回函式的執行結果,就是我們剛才說的函式的因變數。一個函式要執行的程式碼塊(要做的事情)也是透過縮排的方式來表示的,跟之前分支和迴圈結構的程式碼塊是一樣的。大家不要忘了def那一行的最後面還有一個:,之前提醒過大家,那是在英文輸入法狀態下輸入的冒號。
我們可以透過函式對上面的程式碼進行重構。 所謂重構,是在不影響程式碼執行結果的前提下對程式碼的結構進行調整。重構之後的程式碼如下所示。
""
"
輸入M和N計算C(M,N)
Version: 0.1
Author: 駱昊
"
""
# 定義函式:def是定義函式的關鍵字、fac是函式名,num是引數(自變數)
def fac(num):
""
"求階乘"
""
result =
1
for n in
range(
1, num +
1):
result *= n
# 返回num的階乘(因變數)
return result
m =
int(input(
'm = '))
n =
int(input(
'n = '))
# 當需要計算階乘的時候不用再寫重複程式碼而是直接呼叫函式fac
# 呼叫函式的語法是在函式名後面跟上圓括號並傳入引數
print(fac(m)
// fac(n) // fac(m - n))
函式的引數
引數的預設值
如果函式中沒有return語句,那麼函式預設返回代表空值的None。另外,在定義函式時,函式也可以沒有自變數,但是函式名後面的圓括號是必須有的。Python中還允許函式的引數擁有預設值,我們可以把上一課“CRAPSdubo遊戲”的搖篩子獲得點數的功能封裝成函式,程式碼如下所示。
"""
引數的預設值1
Version: 0.1
Author: 駱昊
"""
from random
import randint
# 定義搖篩子的函式,n表示篩子的個數,預設值為2
def roll_dice(n=2):
"""搖篩子返回總的點數"""
total = 0
for _ in range(n):
total += randint(1, 6)
return total
# 如果沒有指定引數,那麼n使用預設值2,表示搖兩顆篩子
print(roll_dice())
# 傳入引數3,變數n被賦值為3,表示搖三顆篩子獲得點數
print(roll_dice(3))
我們再來看一個更為簡單的例子。
"""
引數的預設值2
Version: 0.1
Author: 駱昊
"""
def
add
(a=
0, b=
0, c=
0):
"""三個數相加求和"""
return a + b + c
# 呼叫add函式,沒有傳入引數,那麼a、b、c都使用預設值0
print(add()) # 0
# 呼叫add函式,傳入一個引數,那麼該引數賦值給變數a, 變數b和c使用預設值0
print(add(1)) # 1
# 呼叫add函式,傳入兩個引數,1和2分別賦值給變數a和b,變數c使用預設值0
print(add(1, 2)) # 3
# 呼叫add函式,傳入三個引數,分別賦值給a、b、c三個變數
print(add(1, 2, 3)) # 6
# 傳遞引數時可以不按照設定的順序進行傳遞,但是要用“引數名=引數值”的形式
print(add(c=50, a=100, b=200)) # 350
注意:帶預設值的引數必須放在不帶預設值的引數之後,否則將產生SyntaxError錯誤,錯誤訊息是:non-default argument follows default argument,翻譯成中文的意思是“沒有預設值的引數放在了帶預設值的引數後面”。
可變引數
接下來,我們還可以實現一個對任意多個數求和的add函式,因為Python語言中的函式可以透過星號表示式語法來支援可變引數。所謂可變引數指的是在呼叫函式時,可以向函式傳入0個或任意多個引數。將來我們以團隊協作的方式開發商業專案時,很有可能要設計函式給其他人使用,但有的時候我們並不知道函式的呼叫者會向該函式傳入多少個引數,這個時候可變引數就可以派上用場。下面的程式碼演示了用可變引數實現對任意多個數求和的add函式。
"""
可變引數
Version: 0.1
Author: 駱昊
"""
# 用星號表示式來表示args可以接收0個或任意多個引數
def add(*args):
total = 0
# 可變引數可以放在for迴圈中取出每個引數的值
for val in args:
total += val
return total
# 在呼叫add函式時可以傳入0個或任意多個引數
print(add())
print(add(1))
print(add(1, 2))
print(add(1, 2, 3))
print(add(1, 3, 5, 7, 9))
用模組管理函式
不管用什麼樣的程式語言來寫程式碼,給變數、函式起名字都是一個讓人頭疼的問題,因為我們會遇到 命名衝突這種尷尬的情況。最簡單的場景就是在同一個.py檔案中定義了兩個同名的函式,如下所示。
def
foo
():
print(
'hello, world!')
def
foo
():
print(
'goodbye, world!')
foo()
# 大家猜猜呼叫foo函式會輸出什麼
當然上面的這種情況我們很容易就能避免,但是如果專案是團隊協作多人開發的時候,團隊中可能有多個程式設計師都定義了名為foo的函式,這種情況下怎麼解決命名衝突呢?答案其實很簡單,Python中每個檔案就代表了一個模組(module),我們在不同的模組中可以有同名的函式,在使用函式的時候我們透過import關鍵字匯入指定的模組再使用 完全限定名的呼叫方式就可以區分到底要使用的是哪個模組中的foo函式,程式碼如下所示。
module1.py
def
foo
():
print(
'hello, world!')
module2.py
def
foo
():
print(
'goodbye, world!')
test.py
import module1
import module2
# 用“模組名.函式名”的方式(完全限定名)呼叫函式,
module1.foo() # hello, world!
module2.foo() # goodbye, world!
在匯入模組時,還可以使用as關鍵字對模組進行別名,這樣我們可以使用更為簡短的完全限定名。
test.py
import module1
as m1
import module2
as m2
m1.foo()
# hello, world!
m2.foo() # goodbye, world!
上面的程式碼我們匯入了定義函式的模組,我們也可以使用from...import...語法從模組中直接匯入需要使用的函式,程式碼如下所示。
test.py
from module1
import foo
foo() # hello, world!
from module2
import foo
foo() # goodbye, world!
但是,如果我們如果從兩個不同的模組中匯入了同名的函式,後匯入的函式會覆蓋掉先前的匯入,就像下面的程式碼中,呼叫foo會輸出hello, world!,因為我們先匯入了module2的foo,後匯入了module1的foo 。如果兩個from...import...反過來寫,就是另外一番光景了。
test.py
from module2
import foo
from module1
import foo
foo()
# hello, world!
如果想在上面的程式碼中同時使用來自兩個模組中的foo函式也是有辦法的,大家可能已經猜到了,還是用as關鍵字對匯入的函式進行別名,程式碼如下所示。
test.py
from module1
import foo
as f1
from module2
import foo
as f2
f1()
# hello, world!
f2() # goodbye, world!
標準庫中的模組和函式
Python標準庫中提供了大量的模組和函式來簡化我們的開發工作,我們之前用過的random模組就為我們提供了生成隨機數和進行隨機抽樣的函式;而time模組則提供了和時間操作相關的函式;上面求階乘的函式在Python標準庫中的math模組中已經有了,實際開發中並不需要我們自己編寫,而math模組中還包括了計算正弦、餘弦、指數、對數等一系列的數學函式。隨著我們進一步的學習Python程式設計知識,我們還會用到更多的模組和函式。
Python標準庫中還有一類函式是不需要import就能夠直接使用的,我們將其稱之為內建函式,這些內建函式都是很有用也是最常用的,下面的表格列出了一部分的內建函式。
簡單的總結
函式是功能相對獨立且會重複使用的程式碼的封裝。學會使用定義和使用函式,就能夠寫出更為優質的程式碼。當然,Python語言的標準庫中已經為我們提供了大量的模組和常用的函式,用好這些模組和函式就能夠用更少的程式碼做更多的事情。
Python 900集全套影片教程(全家桶)
你們要的Python影片教程,我也整理好了,嫌看字累,影片給安排上,寵不寵粉就說吧!
學習的可以留言或者私我:“Python” 獲取!
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/69923331/viewspace-2701433/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 從零開始學Python:20課-函式使用進階Python函式
- 從零開始學Python:第十課-函式和字串的應用Python函式字串
- 從零開始學Python:21課-函式的高階應用Python函式
- 從零開始學PythonPython
- 從零開始學Python—第六課:迴圈結構Python
- 【從零開始學習 MySql 資料庫】(2) 函式MySql資料庫函式
- 【從零開始學習Oracle資料庫】(2)函式Oracle資料庫函式
- 從零開始學Python:第22課-Python標準庫初探Python
- 從零開始學Python:第十三課-列表和元組的應用Python
- 從零開始學Python:19課-使用PyCharm開發Python應用程式PythonPyCharm
- 《從零開始學Swift》學習筆記(Day 40)——解構函式Swift筆記函式
- 《從零開始學Swift》學習筆記(Day 21)——函式返回值Swift筆記函式
- 從零開始學Python:第九課-常用資料結構之字串Python資料結構字串
- 從零開始學機器學習——線性和多項式迴歸機器學習
- 從零開始的Python學習Episode 15——正規表示式Python
- 《Python深度學習從零開始學》簡介Python深度學習
- 《從零開始學Swift》學習筆記(Day 37)——預設建構函式Swift筆記函式
- 《從零開始學Swift》學習筆記(Day 39)——建構函式過載Swift筆記函式
- 《從零開始學Swift》學習筆記(Day 19)——函式引數傳遞Swift筆記函式
- 從零開始學Python:第十一課-常用資料結構之列表Python資料結構
- Python從零開始——學習Python的個人方法Python
- 從零開始學Python(八):Python多執行緒和佇列Python執行緒佇列
- 《從零開始學Swift》學習筆記(Day 51)——擴充套件建構函式Swift筆記套件函式
- 《從零開始學Swift》學習筆記(Day43)——建構函式繼承Swift筆記函式繼承
- 從零開始學習KafkaKafka
- 從零開始學習機器學習機器學習
- 【ROS】從零開始學ROSROS
- 從零開始學習laravelLaravel
- Python 函式和模組Python函式
- 從零開始學Python:第十二課-常用資料結構之元組Python資料結構
- python Scrapy 從零開始學習筆記(二)Python筆記
- python Scrapy 從零開始學習筆記(一)Python筆記
- 《從零開始學Python網路爬蟲》概要Python爬蟲
- 從零開始學 Python 之基礎語法Python
- Android從零開始:建立樣式和主題Android
- 【從零開始學習Oracle資料庫】(3)函式與子查詢和連線查詢Oracle資料庫函式
- 【從零開始學習 MySql 資料庫】(3) 函式與子查詢和連線查詢MySql資料庫函式
- 從零開始學 Spring BootSpring Boot