我們在撰寫程式過程中,常會希望有現成的函數可以達到我們想要的功能,但有時偏偏沒有或者有時在程式中多次用到某些功能,此時我們可以將這些功能自己寫成函數,以後要使用的時候直接呼叫即可,一方面可以縮短程式長度,另一方面程式可讀性也會變好,維護上也相對容易。
7-1 函數的建立
Python函數建立的語法如下:
def 函數名稱(參數1, 參數2, 參數3,…):
程式區塊
return
回傳值1, 回傳值2, 回傳值3,…
<注意事項>
1.
函數可以有多個參數亦可沒有參數。
2.
若函數需要有回傳值,則必須在程式區塊加上return。函數可以有多個回傳值亦可沒有回傳值。有回傳值則可將結果指定給變數。
3.
如直接輸入參數值需注意順序,若擔心輸入順序錯誤,則可在輸入參數時加上參數名稱,此時就不需要擔心順序問題。
4. 若希望有些參數為必填,則可以將該參數設定預設值,設定方式為在設定參數時指定數值且必須放在參數的最後面。
程式碼
#建立函數(1)(輾轉相除法-最大公因數)
def
gcd(x,y):
if x==y:
return x
else:
while x!=y:
if x>=y: x=x-y
if x<y : y=y-x
return x
print(gcd(42,36))
Python畫面
程式碼
#建立函數(2)(BMI)
def
BMI(weight,height):
return weight/((height/100)**2)
w=75;h=183
print("75Kg,183公分,BMI為{}".format(BMI(weight=w,height=h)))
Python畫面
程式碼
#建立函數(3)(找取方程式的根-牛頓法)
def
gradient_decent_1d(f,df,x=1,acc=1e-03,detail=False):
times=1
x2=x-eval(f)/eval(df)
if detail==True:print("step
{}:{}".format(times,x2))
while abs(x2-x)>=acc:
times+=1
x=x2; x2=x-eval(f)/eval(df)
if detail==True:print("step
{}:{}".format(times,x2))
return "root is {} ; accurancy is
{}".format(x2,acc)
f1="x**2-2"
; df1="2*x"
print("使用(不修改)預設值".center(30,"="))
print(gradient_decent_1d(f=f1,
df=df1))
print("修改預設值detail為True".center(30,"="))
print(gradient_decent_1d(f=f1,
df=df1, detail=True))
print("修改預設值detail為True且acc=1e-07".center(30,"="))
print(gradient_decent_1d(f=f1, df=df1, detail=True,acc=1e-07))
Python畫面
以上例子我們給了三個預設值,其中acc(精確度)預設為1e-03;detail(牛頓法執行細節)預設為False。當不修改預設值時,只需數入f與df,結果會直接回傳方程式的根與所採用的精確度。當修改預設值時,回傳的結果也會有相對應的修改。
<注意>函數的變數有預設值時需注意的陷阱,參考此文。
7-2 變數使用的範圍-區域變數(Local Variable)與全域變數(Global Variable)
在許多程式語言中都有區域變數與全域變數的概念,在Python中,在函數內定義的變數稱為區域變數;在函數外定義的變數稱為全域變數。兩者無法互相變更值,即使變數名稱設定一樣。以下用一個簡單範例說明。
程式碼
#變數使用範圍(1)
x1=1 #全域變數
def
test():
x1=100
#區域變數
print("區域變數x1:{}".format(x1))
test()
print("全域變數x1:{}".format(x1))
Python畫面
我們可以看到函數中的x1=100並未將函數外的x1=1修改,故函數內的變數不會影響函數外的變數。但是,如果真的有需求要在函數內使用函數外的變數,就必須將函數內的變數宣告成全域變數,寫法就是在變數前面加上global就可以在函數內使用函數外的變數。
程式碼
#變數使用範圍(2)
x1=1 #全域變數
def
test():
global x1,x2
x1=100
x2="Hello"
print("函數內變數x1:{}".format(x1))
print("函數內變數x2:{}".format(x2))
test()
x2="Welcome"
print("函數外變數x1:{}".format(x1))
print("函數外變數x2:{}".format(x2))
Python畫面
程式碼
#區域變數與全域面數的應用-猜數字遊戲
import
random
def
suggest_num_game():
global Min,Max
target=int(random.random()*100)
guess=int(input("===目標在{}~{}之間===".format(Min,Max)))
while True:
if guess==target:
print("答對了~ 答案是{}".format(target));break
else:
if guess<target:Min=guess
if guess>target:Max=guess
guess=int(input("===目標在{}~{}之間===".format(Min,Max)))
Min=int(input("請輸入猜測數字範圍最小值..."))
Max=int(input("請輸入猜測數字範圍最大值..."))
suggest_num_game()
Python畫面
7-3
函數無限參數的設定
在參數設定時,前面附帶一個*號,則代表可以無限輸入參數,並且會將輸入的參數打包成tuple型態供函數內部程式使用;若是前面附帶**號,亦可代表可以無限輸入參數,但會將輸入的參數打包成dict型態供函數內部程式使用。以下用簡單的例子說明一下:
程式碼
#函數參數的進階設定(1)-自訂平均數函數
def
avg(*num):
a=0
for n in num:
a+=n/len(num)
return a
print(avg(1,2,3,4,5,6))
print(avg(1,1,1))
print(avg(-2,-1,1,2))
print(avg())
Python畫面
程式碼
#函數參數的進階設定(2)-輸入個人資料
def
personal_list(**detail):
print("{:<10s}{:<10s}{:<10s}{:<10s}".format(detail.get("Name"),detail.get("Job"),detail.get("Age"),detail.get("Birth")))
print("{:<10s}{:<10s}{:<10s}{:<10s}".format("Name","Job","Age","Birth"))
personal_list(Name="ShawnH",Job="Engineer",Age="34",Birth="1988/11/18",Gender="Male")
Python畫面
最後,在函數的訓練當中,最有名的莫過於河內塔問題了,這個問題牽扯到遞迴數列的觀念,所以如何在程式中用函數寫出遞迴的效果也是一個重要的學習知識,這就是為什麼講到函數都會帶河內塔問題的訓練了。以下我們用上面學到的知識來寫出河內塔問題的解。
程式碼
#河內塔問題
def
Hanoi(A,B,C,disk=2):
if disk==1: print("{}移到{}".format(A,C),end="-")
if disk>1:
Hanoi(A,C,B,disk=disk-1)
print("{}移到{}".format(A,C),end="-")
Hanoi(B,A,C,disk=disk-1)
Hanoi("A","B","C",disk=4)
Python畫面
留言
張貼留言