從 JavaScript 角度學 Python(8) - BMI 計算(1)

前言

接下來這一篇算是收割前面幾個章節的章節小練習,基本上我是盡量規劃每過幾個章節就有一些小作業、小東西,最主要是希望這個系列不只是學習 Python 而是希望透過實際一些小練習來讓加深印象。

小作業

相信許多人在學習程式語言的時候,應該很常遇到 BMI 計算的小作業,不外乎這邊我也是一樣會使用 BMI 計算當作小練習,而接下來小作業的功能很小,剛剛好適合練習:

小功能

當然這邊為了完成條件製作,可能會使用到一些前面完全沒有聊過、講過的語法,畢竟作業在製作上都會有一定難度,所以這邊也是為了要訓練 Google 的技巧,透過 Google 去學習額外的許多知識。

廢話也差不多了,接下來先讓我們看一段可能、大概、或許、應該你已經看到膩的 BMI 公式:

1
BMI = 體重(公斤) / 身高2(公尺2)

很好,相信你看到這邊你已經非常興奮的知道怎麼做了。

所以這一篇就到這邊結束

前面開玩笑的,怎麼可能就這樣結束呢?所以一開始前面就先以平易近人的簡易 JavaScript BMI 計算來寫一遍,畢竟我們是從 JavaScript 角度學 Python 你說是吧?

(運作邏輯與程式碼這邊就不再著墨說明。)

1
2
3
4
5
6
// 身高 175 體重 68
((68 / ((175 ** 2) / 100)) * 100).toFixed(2); // 22.20
// 身高 178 體重 75
((75 / ((178 ** 2) / 100)) * 100).toFixed(2); // 23.67
// 身高 161 體重 45
((45 / ((161 ** 2) / 100)) * 100).toFixed(2); // 17.36

前幾個章節的函式有聊到可以將重複性的行為給包裝起來,上方我們可以注意到,除了 體重身高 是會隨著使用者輸入而變化之外,其他參數都是固定的,因此我們就可以包裝成一個函式直接重複呼叫:

1
2
3
4
5
6
7
function bmi (kg, cm) {
console.log('BMI 計算:', ((kg / ((cm ** 2) / 100)) * 100).toFixed(2));
}

bmi(68, 175); // 22.2
bmi(75, 178); // 23.67
bmi(45, 161); // 17.36

看完平易近人的 JavaScript 後,讓我們回到我們這一次的目標 Python 吧!

那麼上面的 BMI 計算如果要改寫成 Python 的版本又該如何撰寫呢?一開始難度先不拉那麼高,讓我們一步一腳印慢慢打穩基礎之後再來挑戰更難的,所以一開始先試著撰寫跟 JavaScript 版本一樣還沒包裝成函式之前的方式:

1
2
3
4
5
6
# 身高 175 體重 68
print(68 / ((175 ** 2) / 100) * 100) # 22.20408163265306
# 身高 178 體重 75
print(75 / ((178 ** 2) / 100) * 100) # 23.671253629592226
# 身高 161 體重 45
print(45 / ((161 ** 2) / 100) * 100) # 17.36044134099765

基本上我們可以看到輸出的結果中小數點超級的多,但是在這邊我們只取小數點第二位。

那…只取小數點第二位的話我們這邊該怎麼做呢?在 Python 中有一個函式叫做 round() 可以幫助我們四捨五入取得特定小數點:

1
round(x, y)
  • x 要四捨五入的表達式
  • y 要取得小數點第幾位的表達式

因此接下來我們就直接套用 round 函式:

1
2
3
print(round(68 / ((175 ** 2) / 100) * 100, 2)) # 22.20
print(round(75 / ((178 ** 2) / 100) * 100, 2)) # 23.67
print(round(45 / ((161 ** 2) / 100) * 100, 2)) # 17.36

要注意 round 函式若是沒有傳入 y 參數的話,預設是會直接將小數點全部四捨五入:

1
2
3
print(round(68 / ((175 ** 2) / 100) * 100)) # 22
print(round(75 / ((178 ** 2) / 100) * 100)) # 24
print(round(45 / ((161 ** 2) / 100) * 100)) # 17

那麼透過上面程式碼我們也可以得知基本上也是除了 身高體重 之外都不會有任何變動,所以搭配函式之後我們可以這樣寫:

1
2
3
4
5
6
def bmi (kg, cm):
print('BMI 計算結果:', round((kg / ((cm ** 2) / 100)) * 100, 2))

bmi(68, 175) # BMI 計算結果:22.2
bmi(75, 178) # BMI 計算結果:23.67
bmi(45, 161) # BMI 計算結果:17.36

除此之外你也可以試著挑戰使用前面所學的 lambda 改寫程式碼,讓整體程式碼更短更簡潔:

1
2
3
4
bmi = lambda kg, cm: print('BMI 計算結果:', round((kg / ((cm ** 2) / 100)) * 100, 2))
bmi(68, 175) # BMI 計算結果:22.2
bmi(75, 178) # BMI 計算結果:23.67
bmi(45, 161) # BMI 計算結果:17.36

嘗試使用 lambda 之後有沒有很想把全部程式碼改用 lambda 呢?

lambda

當然如果你不想使用 BMI 計算當作練習的話也可以考慮使用別的,例如:匯率、單位計算等等,假設你很沒有想法的話,我個人推薦 這個網站 的計算機,任何一個你都可以去撈出來試著研究製作練習看看。

字串組合

這邊也額外聊一下關於字串相加的部分,為什麼會講到這個呢?主要原因是每個人製作作業呈現的方式不一定,而這邊可能會遇到一些小雷點,所以就順便聊一下關於字串組合的部分。

在前一篇我們已經遇到一個雷點是關於 整數字串 相加的雷點,那麼在早期我們在寫 JavaScript 中主要都是使用加號運算子達到字串相加的需求,而這又稱之為字串連結 or 字串相加:

1
console.log('第'+ day +'天');

而在 ES6 之後出了一個非常非常方便的語法叫做樣板字面值 (Template literals) 的新語法,在開發上組合字串時是非常方便的,尤其是組合 DOM 的時候:

1
console.log(`第${day}天`);

那麼 Python 呢?前面我們已經嘗試過所謂的字串連結,如果傳入的不是相同型別,例如:整數 (int) 那麼就必須做型別轉換:

1
2
day = 1
print('第'+ str(day) +'天')

而這種字串相加的方式其實非常麻煩,你必須一直輸入 '"+ 等符號,那…Python 也有跟 JavaScript 一樣類似的樣板字面值 (Template literals) 語法嗎?嚴格說起來是有的,只是在 Python 中稱之為「 字串格式化(String formatting) 」:

1
2
day = 1
print(f'第{day}天')

不知道你有沒有注意到一件事情,上面的字串格式化範例我並沒有使用 str() 做型別轉換,但是上面範例確實是不會出現錯誤的,因為字串格式化會自己幫你傳入的任何東西都轉換為 String 型別。

你有沒有感覺到字串格式化方便方便超多!

字串格式化(String formatting)

主要使用的方式是在字串最前方加上一個小寫 f or 大寫 F,接著使用 {} 插入要組合的表達式(expression),例如像是變數也可以:

1
2
day = 1
print(f'第{day}天')

剛剛也有提到 {} 內只接受表達式,所以 lambda 也是可以的,只是要記得用類似 IIFE 寫法:

1
print(f'我叫做{ (lambda name: name)("Ray") },你好')

所以上一篇函式的程式碼我們可以改成這樣:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
def fn(day):
print(f'第{day}天')
print('起床')
print('刷牙')
print('運動')
print('中午吃飯')
print('午睡')
print('下午運動')
print('晚上吃飯')
print('晚上洗澡')
print('睡覺')
print('---------')

fn(1)

相較之下使用字串格式化會比使用字串連結較簡潔好寫而且也不用,最後也附上 JavaScript 與 Python 兩者都改成相同的 BMI 計算語法比較:

BMI 計算

最後就讓我們使用迷因結束今天的回合吧:

Python 讚

優化 BMI 計算

最後的最後,算是簡單優化一下 BMI 計算功能而已,延續上方的 BMI 練習題目,我們可以試著在 BMI 中增加判斷式,例如:

  • 傳入的參數不可以小於 0,當若小於任一參數小於 0 的時候,就要中斷程式碼並輸出訊息
  • 可以判斷體重過輕、正常與過重,並輸出訊息
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
def bmi (kg, cm):
if kg <= 0:
return print('體重輸入不正確')
if cm <= 0:
return print('身高輸入不正確')

bmiNum = round((kg / ((cm ** 2) / 100)) * 100, 2)

if bmiNum < 18.5:
print(f'你目前的 BMI 是:{bmiNum},介於過輕範圍內。')
elif 18.5 >= bmiNum < 24:
print(f'你目前的 BMI 是:{bmiNum},介於正常範圍內。')
elif 24 >= bmiNum < 27:
print(f'你目前的 BMI 是:{bmiNum},介於過重範圍內。')
elif 27 >= bmiNum < 30:
print(f'你目前的 BMI 是:{bmiNum},介於輕度範圍內。')
elif 30 >= bmiNum < 35:
print(f'你目前的 BMI 是:{bmiNum},介於中度範圍內。')
elif bmiNum >= 35:
print(f'你目前的 BMI 是:{bmiNum},介於中度範圍內。')
else:
print('計算錯誤。')

bmi(68, 175) # 你目前的 BMI 是: 22.2 介於過重範圍內。
bmi(95, 185) # 你目前的 BMI 是: 27.76 介於中度範圍內。

今天這一份程式碼將會放在這個儲存庫:https://github.com/hsiangfeng/javascript-to-python

參考文獻

作者的話

OH!NO!今天本來要做最後一片花雕醉雞,結果打開之後發現雞肉已經臭掉了…事實證明千萬不要抓剛剛好過期那天處理全部的雞肉。

關於兔兔們

兔法無邊

Liker 讚賞 (拍手)

如果這一篇筆記文章對你有幫助,希望可以求點支持或 牡蠣 鼓勵 (ノД`)・゜・。

Liker 是一個按讚(拍手)的讚賞機制,每一篇文章最多可以按五下(拍手),按讚過程你是完全不用付費的(除非你想要每個月贊助我 :D),你只需要登入帳號就可以開始按讚。
而 Liker 會依據按讚數量分配獎金給創作者,所以如果你願意按個讚我會非常感謝你唷。

Google AD

撰寫一篇文章其實真的很花時間,如果你願意「關閉 Adblock (廣告阻擋器)」來支持我的話,我會非常感謝你 ヽ(・∀・)ノ