iT邦幫忙

2021 iThome 鐵人賽

DAY 8
1
Software Development

從 JavaScript 角度學 Python系列 第 8

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

  • 分享至 

  • xImage
  •  

前言

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

小作業

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

https://ithelp.ithome.com.tw/upload/images/20210908/20119486CfSEJ1u4ck.png

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

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

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

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

所以這一篇就到這邊結束

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

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

// 身高 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

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

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 版本一樣還沒包裝成函式之前的方式:

# 身高 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() 可以幫助我們四捨五入取得特定小數點:

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

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

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 參數的話,預設是會直接將小數點全部四捨五入:

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

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

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 改寫程式碼,讓整體程式碼更短更簡潔:

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 呢?

https://ithelp.ithome.com.tw/upload/images/20210908/20119486IApcUSJoxh.png

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

字串組合

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

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

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

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

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

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

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

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

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

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

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

https://ithelp.ithome.com.tw/upload/images/20210908/20119486BgG0kKADR5.png

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

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

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

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

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

def fn(day):
  print(f'第{day}天')
  print('起床')
  print('刷牙')
  print('運動')
  print('中午吃飯')
  print('午睡')
  print('下午運動')
  print('晚上吃飯')
  print('晚上洗澡')
  print('睡覺')
  print('---------')

fn(1)

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

https://ithelp.ithome.com.tw/upload/images/20210908/20119486iDOOANNb4q.png

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

https://ithelp.ithome.com.tw/upload/images/20210908/201194869nD9CVpZev.png

優化 BMI 計算

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

  • 傳入的參數不可以小於 0,當若小於任一參數小於 0 的時候,就要中斷程式碼並輸出訊息
  • 可以判斷體重過輕、正常與過重,並輸出訊息
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!今天本來要做最後一片花雕醉雞,結果打開之後發現雞肉已經臭掉了...事實證明千萬不要抓剛剛好過期那天處理全部的雞肉。

關於兔兔們

兔法無邊


上一篇
從 JavaScript 角度學 Python(7) - 條件與迴圈
下一篇
從 JavaScript 角度學 Python(9) - 容器型別(上)
系列文
從 JavaScript 角度學 Python31
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言