iT邦幫忙

3

【Python 超入門】(10) 自定義函數介紹- 主人向他的機器人管家抱怨:「你跟我這麼多年了,也該了解我們家的習慣了吧?」

大家好,我是「心原一馬」,內心原來一心喜歡打程式碼。
現在科技進步神速的時代,
說不定未來機器人管家普及,能夠幫人類打理各種家中雜務也不是夢想。

從前,諸如日常瑣事譬如「煮飯、洗衣、倒垃圾…」等等,
媽媽說「新好男人要會處理家務」推給爸爸,
爸爸說「小孩長大了要學做家事」推給姐姐,
姐姐說「她要準備大學聯考」推給弟弟妹妹做,
弟妹說「家中小狗每天只會吃跟玩耍」推給小狗做。
未來,說不定推給機器人管家做,家中成員不再爭吵。

以下給大家講講心原一馬腦洞大開的未來故事劇情來帶大家認識函數這個概念:

故事: 這隻機器人還真不知變通

在未來機器人有能力幫人類打理各種家中雜務的年代…
一天早晨,主人跟他的機器人管家小白說,
「嘿,小白,我出門去上班,你等等去幫忙洗衣服,下午五點鐘時去煮飯。」
小白說道:「主人,機器人絕對服從人類的指令,但是您下的指令不夠明確,無法執行。」
主人說:「不就是叫你洗衣服煮飯嗎?」
小白:「洗衣服這句話有歧義。你沒有講清楚你要我用手洗還是放到洗衣機洗?」
小白:「另外你沒有講清楚洗衣服要洗幾件; 要洗衣服那就不洗褲子的意思嗎?」
主人:「喂,這年代還有人在用手洗衣服的嗎?」
主人:「另外,人類說洗衣服的時候,表示衣服褲子都要洗的意思。」

小白:「哦~ 原來是這樣喔。我覺得你們人類的語言有時候很奇怪耶~」
小白:「像是你們晚餐前會說「開飯囉」,所以那一餐如果吃麵的話,不是應該說「開麵囉」才合邏輯嗎?」
主人:「呃…這個…」
主人哭笑不得… 這年代,語音辯識都這麼發達了,
機器人都可以跟人類聊天了,
居然自己家的小白連人類的常識都不太懂,
早知當初不要為了省錢買二手的機器人管家了。

來給小白定義個函數吧

小白:「為了使用者的安全著想,您一定要下非常明確的指令我才能夠執行的。」
主人:「喂喂,你前天才幫忙洗過衣服的。」
小白:「也許您今天想洗衣服的方式有變,我必須做嚴謹的確認才行。」
大概主人也有點煩了,說:「好,小白我跟你說,你看到浴室的洗衣籃了嗎?」
小白: 「看到了。」
主人: 「以後我下洗衣服這個指令時,你就把洗衣籃裡的衣物全部放進洗衣機裡,然後按下洗衣機開關。不必再問說用手洗還是放到洗衣機洗?要洗幾件?知道嗎?」
小白: 「哦哦~ 知道了,你這樣講我清楚多了。」

自定義函數- 把常常在程式碼中使用的指令包裝起來

好的,回到我們的教學正文。
函數可以把它想成是把常做的事情用一個指令包裝起來

例如我們之前教過幾個內建函數:
print(字串): 在螢幕上顯示出字串
input() : 取得使用者輸入的字串
str(變數): 將數字型態的變數轉換成字串型態
int(變數): 將字串型態的變數轉換成數字型態
len(列表): 取得列表的元素個數

以上是程式設計師們可能會常用到的功能,
所以python設計者把它寫好讓程式設計師可以直接使用。
可是有時候我們也有需要自訂函數的狀況。

以下是基礎的函數定義方法:

def 函數():
    要執行的程式碼1
    要執行的程式碼2
    …
    要執行的程式碼N

定義函數時,函數名稱後面會加上一組小括號,後面再加冒號,
與之前幾篇介紹if-else邏輯和for/while迴圈時一樣,
要放進函數中的程式碼需要空四格做為縮排。

例如故事中主人希望小白去洗衣服的指令,它的邏輯大概是這樣的:
(請注意,以下只是表達一段程式邏輯,並不是真正可執行的程式碼哦~)

for 衣物 in 洗衣籃:
    把衣物放進洗衣機裡面
按下洗衣機的開關

可是如果每次主人叫小白去洗衣服的時候,
都要把這些指令跟他清楚的交代,
這樣實在太麻煩了,
因此,我們可以定義一個洗衣服函數,
然後把洗衣服的明確指令放進去,

def 洗衣服():
    for 衣物 in 洗衣籃:
        把衣物放進洗衣機裡面
    按下洗衣機的開關

這樣以後主人要叫小白去洗衣服時,
只要叫告訴它去洗衣服
就不必再把這些細節都告訴它了。

定義有參數的函數

更進階的,你也可以讓函數有「輸入」和「輸出」:

def 函數(參數):
    要執行的程式碼1
    要執行的程式碼2
    …
    要執行的程式碼N
    return 結果

學習兩個新的詞: 參數回傳值
參數是從外部輸入給函數使用的資料
回傳值是從函數傳回給主程式的資料,在python內會用return這個關鍵字取得回傳值。

簡易範例: 請問芳齡?

我們知道人類在計算年紀有「虛歲」和「實歲」兩種算法,
虛歲比實歲多一歲。
我們結合上一篇教的【Python 超入門】(9) input()函數- 使用者跟電腦對話的方法
讓使用者輸入實歲年齡,
程式會幫忙計算出他的虛歲年齡。如下:

#定義一個函數,回傳輸入的數字加一
def addOne(x):
    return x+1

n= int(input("你今年實歲幾歲?")) # 取得使用者輸入的實歲年齡,把字串轉換成數字
year = addOne(n) #計算他的虛歲年齡
print("你今年虛歲"+str(year)+"歲")

範例: 計算全班分數平均

現在要把前幾堂課學過的內容靈活運用囉~
假設我們現在用一個列表來存班上每個人的數學考試分數,
例如:

scores = [50,60,35,20,40,0]

這時如果我們想要計算班平均分數的話,
我們可能會這樣寫:

scores = [50,60,35,20,40,0]
totolScore = 0 #用totolScore變數儲存全班的分數總和
for s in scores: #在迴圈中把每個人的分數加總
    totolScore +=s
average = totolScore/len(scores) #平均分數= 全班分數/全班人數,len()是計算列表元素個數的內建函數
print(average) #把結果印出來

結果為34.166666666666664
(大家可以拿計算機驗證一下,答案是205/6的結果,
至於為什麼答案不是大家想像中的34.166666666666666
並非今天要討論的重點,
大家心中先有個概念就是電腦計算無窮小數可能會有誤差就行了。)

這樣寫程式會正確,可是如果要一次處理多個班級的資料呢?
例如現在有三個班:

scores1 = [70, 60, 75, 65, 15, 15]
scores2 = [45, 10, 50, 5, 30, 50, 75]
scores3 = [70, 5, 10, 50, 60]

你在把剛剛的程式碼複製三次來改寫試試:

scores1 = [70, 60, 75, 65, 15, 15]
scores2 = [45, 10, 50, 5, 30, 50, 75]
scores3 = [70, 5, 10, 50, 60]

totolScore1 = 0 #用totolScore變數儲存全班的分數總和
for s in scores1: #在迴圈中把每個人的分數加總
    totolScore1 +=s
average1 = totolScore1/len(scores1) #平均分數= 全班分數/全班人數,len()是計算列表元素個數的內建函數
print(average1) #把結果印出來

totolScore2 = 0 #用totolScore變數儲存全班的分數總和
for s in scores2: #在迴圈中把每個人的分數加總
    totolScore2 +=s
average2 = totolScore2/len(scores2) #平均分數= 全班分數/全班人數,len()是計算列表元素個數的內建函數
print(average2) #把結果印出來

totolScore3 = 0 #用totolScore變數儲存全班的分數總和
for s in scores3: #在迴圈中把每個人的分數加總
    totolScore3 +=s
average3 = totolScore3/len(scores3) #平均分數= 全班分數/全班人數,len()是計算列表元素個數的內建函數
print(average3) #把結果印出來

這樣程式碼是不是顯的冗長難讀?
我們可以在這段程式碼之前先定義好計算平均的函數:

def average(scores):
    totolScore = 0
    for s in scores:
        totolScore +=s
    average = totolScore/len(scores)
    return average

再於主程式中呼叫該函數:

def average(scores):
    totolScore = 0
    for s in scores:
        totolScore +=s
    average = totolScore/len(scores)
    return average
    
scores1 = [70, 60, 75, 65, 15, 15]
scores2 = [45, 10, 50, 5, 30, 50, 75]
scores3 = [70, 5, 10, 50, 60]

print(average(scores1))
print(average(scores2))
print(average(scores3))

結果:
50.0
37.857142857142854
39.0

這樣寫程式是不是變得乾淨好讀了呢?
最近教的觀念逐漸變深,
歡迎各位在留言區留下任何疑問或回饋哦~
預計下一篇文章就能進入【Python 超入門】系列的完結篇了~
但心原一馬並不會止步於此,
敬祝各位邦友們學習順利~

結尾彩蛋

什麼?你以為本篇結束了嗎?
故事還有後續呢~

主人交代完機器人管家小白記得洗衣服、煮飯後,就上班去了…
在路上,主人突然想到: 「啊,忘記交代小白說等衣服洗完要晒衣服了,趕快打電話跟它說一下~」
下班回家後,主人發現陽台在晒的衣物好像少了一半,去問小白,
小白說:「哦哦~ 你們人類講話很不嚴謹耶~ 你只有說洗衣服表示衣服褲子都要洗的意思,倒沒說晒衣服也是衣服褲子都要晒的意思啊?」


1 則留言

1
瓦力
iT邦新手 5 級 ‧ 2019-07-11 12:14:29

什麼?【Python 超入門】系列要完結篇了嗎?/images/emoticon/emoticon70.gif

小馬大大的結尾彩蛋
寫的好貼切~
真的就是一個口令一個動作~
(如果這是小孩真的會想掐掐死~XD)
所以 人的腦袋 還是很神奇的啊~~

期待 期待後續的教學~~~

謝謝你欣賞我的文章哦~
如果在「人工智能」的時代真有這種機器人的話,
大概會被當成「人工智障」吧,哈哈哈~
這邊主要是想比喻寫程式語法的嚴謹性。

敬請期待後續的教學~
小馬會繼續努力

我要留言

立即登入留言