从 JavaScript 角度学 Python(14) - BMI 计算(2)

前言

前面章节也算是已经告一个段落了,所以接下来一样来简单实作一下前面的小知识点。

BMI 章节回顾

在第六天的结尾处我们有写了一段简单的 BMI 计算功能:

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('你目前的 BMI 是:', bmiNum, '介於过轻范围内。')
  elif 18.5 >= bmiNum < 24:
    print('你目前的 BMI 是:', bmiNum, '介於正常范围内。')
  elif 24 >= bmiNum < 27:
    print('你目前的 BMI 是:', bmiNum, '介於过重范围内。')
  elif 27 >= bmiNum < 30:
    print('你目前的 BMI 是:', bmiNum, '介於轻度范围内。')
  elif 30 >= bmiNum < 35:
    print('你目前的 BMI 是:', bmiNum, '介於中度范围内。')
  elif bmiNum >= 35:
    print('你目前的 BMI 是:', bmiNum, '介於重度范围内。')
  else:
    print('计算错误。')

print(bmi(68, 175)) # 你目前的 BMI 是: 22.2 介於过重范围内。
print(bmi(95, 185)) # 你目前的 BMI 是: 27.76 介於中度范围内。

接下来我们会将上面的程序码加入一些小功能

https://ithelp.ithome.com.tw/upload/images/20210914/20119486QBRz7uGPWy.png

(上面这张图真好用。)

所以这边我们先来聊一下使用者故事吧。

BMI 使用者故事

  • 使用者可以透过终端机输入身高与体重,而必须是身高优先输入接下来才是体重。
  • 输出结果之前会先出现 Loading 读取中约五秒。
  • 五秒之後会输出结果显示 BMI 值与目前 BMI 介於哪个范围内。
    • 例如:你目前的 BMI 是: 22.2 介於过重范围内。

最後在列一个进阶一点的东西好了

  • 输出的结果必须依据以下范围输出相关的文字颜色
    • 例如:「你目前的 BMI 是: 22.2 介於过重范围内」的这句话的过重必须是橘色。
    • 过轻 - 黄色
    • 正常 - 绿色
    • 轻度 - 黄色
    • 中度 - 橘色
    • 重度 - 红色

那麽看完上方使用者故事之後就准备来实作吧。

往下看之前你也可以先试着自己制作看看,如果没有想法的话,再往下参考我的作法哩。

使用者自定义输入身高与体重

刚好这边的技巧在前一个章节已经有讲到,想必记忆非常深刻,所以我们这边会需要宣告身高与体重这两个变数,但是这边要注意使用者故事有讲到一件事情:

「使用者可以透过终端机输入身高与体重,而必须是身高优先输入接下来才是体重。」

因此这边我们可以知道我们将会使用 input 函式,接下来另一个问题是,使用者所输入的值都会是字串,因此这边应该使用正整数?还是浮点数呢?通常来讲我们在量身高与体重的时候都会有小数点,因此这边会建议使用 float() 包覆 input() 函式:

cm = float(input('请输入您的身高:'))
kg = float(input('请输入您的体重:'))

那麽第一条使用者故事这边算是完成了。

Loading 效果

接下来是关於终端机上呈现 Loading 的效果,这一个效果在使用者故事上有讲到要等五秒

「输出结果之前会先出现 Loading 读取中约五秒。」

这个功能的关键重点技术在於 for loopprint,因此可能会需要跑五次回圈:

for i in range(5):
  print('Loading')

基本上上面的程序码结果就会是跑五次 Loading,但是可能有点不好看,所以我们可以稍微调整一下变成 Loading.....,那麽因此要做到这个效果我们就必须使用 printend 参数,这是什麽意思呢?我们可以看到是五个点点,因此我们可以先将 Loading 文字输出,接下来的点点点都是用回圈输出,那麽预设情况下 print\n 换行,因此我们要改成无换行模式:

print('Loading', end='')
for i in range(5):
  print('.', end='')

上面的结果基本上已经非常接近我们要的效果 Loading.....,接下来就是我们要如何做到点点点是一秒一个点的方式,那麽由於 Python 内建是没有时间相关处理的函式,因此这边就必须额外引入 Python 的 time 模组(import time),而 time 底下有一个 sleep 函式,这个函式主要用途是让程序码暂停你要停止的秒数,所以这一段 sleep 补在 print('.', end='') 结尾处就可以了:

import time

print('Loading', end='')
for i in range(5):
  print('.', end='')
  time.sleep(1) # 让程序码睡一秒

这时候你应该会发现程序码没有即时地出现,当它出现的时候已经是一个完整的 Loading..... 而不是一个点点点出现,这边问题主要是出在 print 参数中有一个 flush 导致的,预设 flushFalse,而这个参数会先将预期要输出的结果放到记忆体中等待回圈全部跑完再一次输出,如果改完 True 的话就会变成不让它将结果放到记忆体中而是直接输出:

import time

print('Loading', end='')
for i in range(5):
  print('.', end='', flush=True)
  time.sleep(1) # 让程序码睡一秒

所以 flush 其实是一个很特别的属性唷~

输出 BMI 结果

这边先整理一下程序码,先将上面 inputLoading 程序码都整合之後再来看一下:

import time

cm = float(input('请输入您的身高:'))
kg = float(input('请输入您的体重:'))

print('Loading', end='')
for i in range(5):
  print('.', end='', flush=True)
  time.sleep(1) # 让程序码睡一秒

那麽其实 BMI 计算这边我就偷懒一下,直接将先前的写好的计算程序码直接拉进来微调就好了:

import time

cm = float(input('请输入您的身高:'))
kg = float(input('请输入您的体重:'))

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('你目前的 BMI 是:', bmiNum, '介於过轻范围内。')
  elif 18.5 >= bmiNum < 24:
    print('你目前的 BMI 是:', bmiNum, '介於正常范围内。')
  elif 24 >= bmiNum < 27:
    print('你目前的 BMI 是:', bmiNum, '介於过重范围内。')
  elif 27 >= bmiNum < 30:
    print('你目前的 BMI 是:', bmiNum, '介於轻度范围内。')
  elif 30 >= bmiNum < 35:
    print('你目前的 BMI 是:', bmiNum, '介於中度范围内。')
  elif bmiNum >= 35:
    print('你目前的 BMI 是:', bmiNum, '介於重度范围内。')
  else:
    print('计算错误。')

print('Loading', end='')
for i in range(5):
  print('.', end='', flush=True)
  time.sleep(1)

bmi(kg, cm)

这边基本上程序码就已经完成八成了,可是你如果尝试输入以上程序码时,会发现 Loading 会与输出结果混在一起,所以这边就要调整一下 for loop 的内容,只要回圈跑到最後一次时,就要变成原本的 \n 换行输出:

print('Loading', end='')
for i in range(5):
  if i < 4:
    print('.', end='', flush=True)
  else:
    print('.', flush=True)
  time.sleep(1)

这样子输出的结果就会正常罗~

文字颜色

其实关於文字颜色的部分相对是比较困难的,刚好在 stack overflow 刚好就有人提出来:

HEADER = '\033[95m'
OKBLUE = '\033[94m'
OKCYAN = '\033[96m'
OKGREEN = '\033[92m'
WARNING = '\033[93m'
FAIL = '\033[91m'
ENDC = '\033[0m'
BOLD = '\033[1m'
UNDERLINE = '\033[4m'

因此我们可以整理成自己的字典来使用:

color = {
  'OKGREEN': '\033[92m',
  'WARNING': '\033[93m',
  'FAIL': '\033[91m',
  'ENDC': '\033[0m',
}

接下来使用方式非常简单,这边就让我用「字串格式化(String formatting)」来重新调整文字颜色:

print(f'你目前的 BMI 是:{bmiNum}介於{color["WARNING"]}过轻{color["ENDC"]}范围内。')

请注意!字典取值的地方要改成双引号,否则会出现 SyntaxError: f-string: unmatched '[' 的错误讯息唷。

那麽这样子就完成了比较进阶的 BMI 计算功能,最後这边也提供完整的范例给予参考:

import time

color = {
  'OKGREEN': '\033[92m',
  'WARNING': '\033[93m',
  'FAIL': '\033[91m',
  'ENDC': '\033[0m',
}

cm = float(input('请输入您的身高:'))
kg = float(input('请输入您的体重:'))

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}介於{color["WARNING"]}过轻{color["ENDC"]}范围内。')
  elif 18.5 >= bmiNum < 24:
    print(f'你目前的 BMI 是:{bmiNum}介於{color["OKGREEN"]}正常{color["ENDC"]}范围内。')
  elif 24 >= bmiNum < 27:
    print(f'你目前的 BMI 是:{bmiNum}介於{color["WARNING"]}过重{color["ENDC"]}范围内。')
  elif 27 >= bmiNum < 30:
    print(f'你目前的 BMI 是:{bmiNum}介於{color["WARNING"]}轻度{color["ENDC"]}范围内。')
  elif 30 >= bmiNum < 35:
    print(f'你目前的 BMI 是:{bmiNum}介於{color["FAIL"]}中度{color["FAIL"]}范围内。')
  elif bmiNum >= 35:
    print(f'你目前的 BMI 是:{bmiNum}介於{color["FAIL"]}重度{color["FAIL"]}范围内。')
  else:
    print('计算错误。')

print('Loading', end='')
for i in range(5):
  if i < 4:
    print('.', end='', flush=True)
  else:
    print('.', flush=True)
  time.sleep(1)
bmi(kg, cm)

今天这一份程序码将会放在这个储存库:https://github.com/hsiangfeng/javascript-to-python

参考文献

作者的话

绍兴醉鸡的口感跟花雕鸡差不多,但是这次似乎没有将绍兴酒的酒味给逼出来有点可惜。

关於兔兔们

兔法无边


<<:  未来狂想:农业生产领域

>>:  [Day14]C# 鸡础观念- 不同层次的阵列~二维阵列

Day14 上上下下左左右右 & 世代差异的沟通术

如果你看到标题秒懂而且联想到梁家辉的话,我只能说,你一定是一个擅长沟通的好PM。 谈到团队内沟通,跟...

Day19 - AVL tree

大家好,我是长风青云。今天是铁人赛第十九天。 这是今天的影片。 来说个题外话。 今天下午我在看云端课...

[Day04 - UI/UX] 确认使用的 UI framework

开始画图之前,先确认好要使用的UI framework,来确认可以使用什麽元件。才不会有实作画面很困...

[Day 3] 你真了解资料吗?试试看视觉化分析吧!

你真了解资料吗?试试看视觉化分析吧! 今日学习目标 探索式分析 (EDA) 聊聊何谓 EDA,为何要...

2022 年 5 大蓝光 ISO 播放器软件

大多数普通媒体播放器都无法播放蓝光ISO档、蓝光光盘以及BD资料夹。在这篇文章中,我将重点介绍市场上...