解决温标转换问题的深度探究
2022-05-13肖靖孙军
肖 靖 孙 军
(牡丹江市教育教学研究院, 黑龙江 牡丹江 157000)
编程是高中阶段信息技术学科重要的知识与能力,是所有高中生的必修课程,其主要研究对象是算法和程序设计。我们都知道程序设计的一般过程可分为四步。首先,分析问题,在分析问题的过程中我们要确定解决问题的方法和对所涉及到的数据进行描述;其次,设计算法,在设计算法的过程中我们要选择描述算法的方法和对算法进行设计;再次,编写程序,在编写程序的过程中我们要选择程序设计的语言并编写程序,本文沿用教材上使用的Python语言对温标转换问题进行深度的探究;最后,运行调试,在运行调试过程中我们要运行编写好的程序,如程序不能按照我们预想的方式运行,要修改编程过程中产生的错误,然后再运行、再调试,直到程序的运行结果符合我们的既定预期为止。本文主要从温标转换程序的功能性和健壮性等方面对教材中原有的程序进行深度探究。
一、程序运行环境
本文所涉及到的编程为与普通高中信息技术教材保持一致和考虑到使用习惯以及程序运行的普遍性和通用性等因素,确定了如下的操作系统、编程语言和集成开发环境:
操作系统及版本Windows11中文版21H2编程语言及版本Python3.8.6集成开发环境及版本Pycharm 2021.3 (Professional Edition)
二、原有程序分析
(一)问题分析及探究
教材中给出的问题是如何将给到的华氏温度转换为摄氏温度?教材中给出解决这个问题的过程是在程序中接收用户输入的华氏温度值,再运用给定的公式计算出该华氏温度对应的摄氏温度,最后再输出摄氏温度的值。
如果对教材中给出的问题进一步深度探究,我们可以将问题变成如何将给到的华氏温度和摄氏温度进行互转,也就是说,假设我们现在给程序输入一个华氏温度的值,程序可以将其对应的摄氏温度的值进行输出;同样我们现在给程序一个摄氏温度的值,程序也可以将其对应的华氏温度的值进行输出。而在给定程序值的时候我们需要指明这是一个摄氏温度还是一个华氏温度以方便程序对其进行相应的转换。
另外,在教材中只是提到了接收用户输入的华氏温度的值,而并没有对华氏温度值的有效性进行验证。我们都知道,如果在一个程序当中开放对用户的输入也就是说程序可以接收用户输入内容的时候,为了保证程序的健壮性,程序自身必须能够对其接收的值进行有效性验证。如果程序缺少有效性验证,则极易引发非预期数据的输入,进而导致程序崩溃无法继续运行。举个例子:教材中的当前程序需要的是一个华氏温度,如果我们输入了诸如“abc”之类的字符串,那么程序就会报出“ValueError: could not convert string to float: 'abc'”这样的错误,为了避免这样的错误发生,程序中就需要补充相关的数据验证功能。即当用户输入的数据不符合程序要求的类型时,程序不会向下继续执行,而会要求用户重新进行输入,直到用户输入的数据符合程序的要求再继续向下执行。
当我们延申了教材原有的问题后就需要对解决这个问题的过程进行继续探究。教材原有的解决过程是在程序中接收用户输入的华氏温度值,再运用给定的公式计算出该华氏温度对应的摄氏温度,最后再输出摄氏温度的值。对原有解决过程的继续探究如下:首先,我们需要将程序接收的参数由一个变为两个,除了需要接收温度的数值外还需要接收温度的类型,也就是说这个温度是华氏温度还是摄氏温度;其次,我们通过程序的循环结构验证用户输入的数据是否符合规范,如果不符合规范则提示用户重新输入符合规范的值再验证,直到用户输入的数据符合程序的要求为止;再次,当用户输入的数据符合规范后,我们通过程序的选择结构要进行如下判断——如果输入的是一个摄氏温度,那么就需要执行摄氏温度转华氏温度的公式,如果输入的是华氏温度,那么就需要执行华氏温度转摄氏温度的公式;最后,将转换后的结果进行输出,展示给用户。
(二)算法分析及探究
通过对以上算法流程图的分析及探究,我们可以清晰地看到原算法流程图为理想状态下采用自上而下执行的顺序结构编程。该程序隐含假设了用户输入的温度值为符合程序计算规范的数字,而且从该算法流程图中可以看出原程序功能单一,即程序只能从华氏温度转为摄氏温度。我们从经过深入探究后的现算法流程图中可以明确地看到如下内容。首先,用户输入的参数比原算法流程图多了一个,给了用户更多的输入选择,即可以输入代表摄氏温度的温度值也可以输入代表华氏温度的温度值;其次,在现算法流程图中也明确体现出对输入参数的数据有效性校验,即如果输入的数据不符合规范则程序会一直要求用户输入,直到符合规范为止;最后,在现算法流程图中对输入符合规范的温度类型进行判断,根据判断的结果执行相应的计算逻辑并输出。
三、新增程序功能并完善数据验证
经过上述的分析问题和设计算法,我们现在就可以根据设计好的算法开始编写程序。在给出我们对解决温标转换问题深度探究后的程序前,我们先回顾一下教材中原有的程序。
(一)原有程序及探究
f = float(input("请输入一个华氏温度:"))c = 5 ∗ (f - 32) / 9print("摄氏温度:", c)
以上即是教材中提供的三行程序代码,现对其进行探究如下。第一行代码定义了一个变量f用于接收用户输入的华氏温度并浮点转换后的值,在该行代码中首先使用了一个Python的内置函数input()让程序暂停等待用户输入内容,为了让用户更明确知道自己要输入的是什么内容,程序的编写者在input()函数中提供了一个字符串——” 请输入一个华氏温度:”来进行说明。如果程序开始运行后,此时会先暂停并在屏幕上显示以上提示内容并等待用户输入一个具体的华氏温度值,当用户输入完毕后input()函数会将用户输入的结果以字符串的形式返回。因字符串类型的值无法正常参与数学运算,所以需要在input()函数外包裹了一个Python内置函数float(),目的是将input()函数返回的字符串转换成浮点类型的数,在float()函数转换的过程中,理想状态下是用户输入了一个数字而非一个字符串。最后将用户输入的华氏温度经转换后的浮点型数值赋值给变量f用于后续的运算。第二行代码定义了一个变量c用于接收华氏温度经公式转换后得到的摄氏温度的值。转换公式是将第一步声明并赋值华氏温度值的变量f减去数值32,得到的差再与数字5相乘最后与数字9相除。最终得到的结果就是华氏温度值经过计算转换为摄氏温度值并赋予变量c。第三行代码直接调用了Python的内置函数print()将第二行声明并赋值转换后摄氏温度的变量c进行打印输出在操作系统终端展示给用户。
以上即是对教材中温标转换问题原程序的探究,可以看出这三行代码中并没有包括对输入数据的验证和华氏温度与摄氏温度互转功能。下面我们继续看现有程序是如何更进一步解决刚才所提到的问题。
(二)现有程序及探究
文件名:temperature_converter.pydef check_type_and_value(param_type, param_value): try: float(param_value) except ValueError: return False else: return param_type == "F" or param_type == "C"if __name__ == "__main__": fc_type = input("请选择要输入的温度类型(华氏温度请输入F 摄氏温度请输入C):").upper() fc_value = input("请输入一个温度数值:") while not check_type_and_value(fc_type, fc_value): print("∗∗提示∗∗: 请输入正确的温度类型和温度数值!") fc_type = input("请选择要输入的温度类型(华氏温度请输入F 摄氏温度请输入C):").upper() fc_value = input("请输入一个温度数值:") fc_value = float(fc_value) if fc_type == "F": c_value = 5 ∗ (fc_value - 32) / 9 print(f"华氏温度 {fc_value}℉ 转换成对应的摄氏温度为 {c_value}℃")else: f_value = fc_value ∗ 9 / 5 + 32 print(f"摄氏温度 {fc_value}℃ 转换成对应的华氏温度为 {f_value}℉")
以上即是对教材中提供的程序深入探究并丰富功能后的现有程序。现对其说明如下。该程序从结构上看分为两部分:上半部分为验证数据的check_type_and_value(param_type, param_value)函数;下半部分为以if __name__ == "__main__":开头的程序执行入口。我们先从下半部分的程序执行入口开始阐述。对于Python语言来说"__main__"是顶层代码执行时候的作用域名,而每个Python源文件都有一个__name__属性,我们通过操作系统的终端直接运行某个Python源文件的时候,其__name__属性的值就会等于"__main__"。因此,我们可以通过此特性来判断其所在的Python源文件是在操作系统终端直接运行还是作为其它程序的第三方模块被导入使用。如果该行代码的运行结果为True,则意味着其所在的文件是在操作系统终端直接运行,那么就会继续运行其if选择结构内的代码;如果该行代码的运行结果为False,则意味着其所在的文件是被其它程序以第三方模块的形式导入使用,那么就不会运行其if选择结构内的代码,而会跳过if选择结构运行其后的代码,若if选择结构后无代码则该Python源文件作为导入内容结束运行。
因为我们是从操作系统终端直接运行该Python源文件,所以在程序入口处if __name__ == "__main__":的执行结果为True,进入if选择结构内继续运行。在其中我们首先定义了两个变量——fc_type和fc_value,分别用来接收温度类型和温度数值,此处接收到的两个变量值都是字符串类型,所使用的input()内置函数在上文已经介绍过,此处不再赘述。值得注意的是对于fc_type变量来说,为了与之后要说明的验证函数check_type_and_value(param_type, param_value)中的逻辑判断标准相符,我们在其后的input()内置函数后又调用了upper()内置函数,该内置函数的作用是返回调用该字符串的副本并将其中的英文字母都转换为大写。
两个变量fc_type和fc_value接收到用户输入想要转换的温度类型和温度值后,我们使用了一个while循环结构配合check_type_and_value(param_type, param_value)函数来对接收到的这两个变量进行验证。如果对两个变量的验证结果符合程序要求的数据格式,那么程序继续往下运行;反之,则重复让用户输入温度类型和温度值的步骤再进行验证,直到用户输入的变量值和变量类型符合程序要求的数据格式为止。下面来看一下我们自定义的check_type_and_value(param_type, param_value)函数,该函数的签名处有两个形参分别为param_type和param_value,目的是用来接收fc_type和fc_value这两个实参的赋值。在函数内部,我们首先通过使用Python的异常处理结构对温度数值进行验证,因为我们接收到的值格式是字符串类型,而我们需要的值格式是浮点型,所以我们使用float()内置函数来将接收到的字符串类型值转换为浮点类型值。而在转换的过程中有可能会出现ValueError类型的异常,故我们需要将转换过程float(param_value)置于try语句的监视下。如果转换不成功则会抛出ValueError类型的异常,被except语句捕获,代表用户输入的温度数值不符合规范返回False让用户重新输入;如果转换成功则会跳过except语句进入到else语句中对param_type参数进行验证。此处,我们对param_type的验证逻辑是该变量的值必需为"F"或"C"其中之一,如果不是"F"或"C"其中之一则通过逻辑运算or的运算结果返回False让用户重新输入,直到用户输入的温度类型和温度数值符合规范为止。
当用户输入的温度类型和温度数值符合规范后,程序继续向下执行对温度数值进行浮点型转换,转换后的温度数值用于之后的运算。温度数值转换完毕后,执行选择结构对温度类型进行判断,如果变量fc_type表示的温度类型值为字符串"F",则代表要转换的温度是华氏温度,就需要执行if分支后的语句;否则的话就表示温度类型为字符串"C",则代表要转换的温度是摄氏温度,就需要执行else分支后的语句。在华氏温度转摄氏温度的计算过程中,我们使用了教材中提供的公式——摄氏温度值 = 5 *(华氏温度值-32)/9;在摄氏温度转华氏温度的计算过程中,我们倒推了教材中提供的公式——华氏温度值 = 摄氏温度值 * 9/5 + 32。得到转换后的温度数值后,我们调用print()内置函数通过格式化字符串常量的方式将结果进行输出显示。
四、运行调试
以上运行过程中加粗文字为我们在程序执行过程中输入的内容。通过上述两次的运行结果我们可以看出,第一次运行华氏温度可以正常转换为摄氏温度;第二次运行我们先故意输入了一个错误的温度类型W,结果程序给予了我们提示,让我们重新输入,然后我们又故意输入了一个错误的温度值36.5abc,同样程序给予了我们提示,让我们重新输入,最后我们输入了符合规范的温度类型C和温度数值36.5,得到了正确的摄氏温度对华氏温度的转换结果输出。
python temperature_converter.py请选择要输入的温度类型(华氏温度请输入F 摄氏温度请输入C):F请输入一个温度数值:97.7华氏温度 97.7℉ 转换成对应的摄氏温度为 36.5℃请选择要输入的温度类型(华氏温度请输入F 摄氏温度请输入C):W请输入一个温度数值:36.5∗∗提示∗∗: 请输入正确的温度类型和温度数值!请选择要输入的温度类型(华氏温度请输入F 摄氏温度请输入C):C请输入一个温度数值:36.5abc∗∗提示∗∗: 请输入正确的温度类型和温度数值!请选择要输入的温度类型(华氏温度请输入F 摄氏温度请输入C):C请输入一个温度数值:36.5摄氏温度 36.5℃ 转换成对应的华氏温度为 97.7℉
五、总结
我们经过对上海科技教育出版社出版的普通高中教科书《信息技术教材(必修1)数据与计算〈第三单元 算法和程序设计——项目六 解决温标转换问题〉》进行了深度探究,在教材原有案例的基础上进行了拓展,对温标转换功能进行了升级,使其可以实现华氏温度和摄氏温度的相互转换。拓展后的源程序还实现了对用户输入数据的校验,使程序的健壮性得到了进一步的提升,达成了教材抛砖引玉的目的。对教材原有案例的深度探究精神更有助于学生编程能力的提高和编程思维的扩展!