本文章大部分内容来自中国大学MOOC网站国家精品课程Python语言程序设计(嵩天、黄天羽、礼欣)。感谢各位老师带来如此优秀的课程供我们学习。
问题描述:
请编写程序将用户输入华氏度转换为摄氏度,或将输入的摄氏度转换为华氏度。
转换算法如下:(C表示摄氏度、F表示华氏度)
C = ( F - 32 ) / 1.8
F = C * 1.8 + 32
10行代码:
#TempConvert.py
TempStr=input("请输入带有符号的温度值:")
if TempStr[-1] in ['F','f']:
C=(eval(TempStr[0:-1])-32)/1.8
print("转换后的温度是{:.2f}C".format(C))
elif TempStr[-1] in ['C','c']:
F=1.8*eval(TempStr[0:-1])+32
print("转换后的温度是{:.2f}F".format(F))
else:
print("输入格式错误")
虽然只有短短10行代码,但其中涉及了python的许多独特语法,下面对其来进行一一解释。
- 注释
#TempConvert.py
与java,c,c++,c#等语言中使用//注释不同,在Python中,#代表注释语句。若是多行注释,则使用’’'作为注释的开头和结尾。
'''这是多行注释第一行
这是多行注释第二行'''
- 缩进制度
if TempStr[-1] in ['F','f']:
C=(eval(TempStr[0:-1])-32)/1.8
print("转换后的温度是{:.2f}C".format(C))
elif TempStr[-1] in ['C','c']:
F=1.8*eval(TempStr[0:-1])+32
print("转换后的温度是{:.2f}F".format(F))
大家可能已经注意到,在该段代码中,并没有像大多数语言一样使用{}来标注一个语句块。那么Python是如何识别代码的层次结构的呢?
Python规定了极为严格的缩进制度,同一层次的代码第一个字母必须对齐,而相邻层次的代码必须保证在整个程序中长度相同的缩进。比如在上述代码片段中,第1行的if和第4行的elif为同一级别的语句,所以它们的首字母必须对齐。而第2,3行的语句是第1行if条件成立的分支,需要与第一行产生一定长度的缩进。第5,6行作为分支语句块和第4行的语句也相差一个层次,故它们也需要在第4行基础上进行一定的缩进,但是该缩进量必须与第2,3行相对第1行的缩进量相同(我们可以理解为第2,3,5,6行代码是同一层次的)。
如果存在多重嵌套或循环的情况,那么任何两个相邻层次之间的缩进量应该是一样的,比如下面这段代码
for i in range(1,DARTS):
x,y=random(),random()
dist=sqrt(x**2+y**2)
if disr<=1.0:
hits=hits+1
该代码第2,3,4行相对第1行的缩进量与第5行相对第4行的缩进量有着严格的一致(4个字符)。
需要注意的是,相邻层次代码之间的缩进量并没有要求,只要在整个程序中保持一致即可,但我们一般使用4个空格或者1个tab键。
- 没有显式说明数据类型的变量
#TempConvert.py
TempStr=input("请输入带有符号的温度值:")
if TempStr[-1] in ['F','f']:
C=(eval(TempStr[0:-1])-32)/1.8
print("转换后的温度是{:.2f}C".format(C))
elif TempStr[-1] in ['C','c']:
F=1.8*eval(TempStr[0:-1])+32
print("转换后的温度是{:.2f}F".format(F))
else:
print("输入格式错误")
让我们重新观察这段代码,有编程经验的我们很容易就能发现TempStr,C,F是3个变量。但我们再仔细观察这三个变量,发现了什么?
没错!这三个变量从来没有声明它们的数据类型。程序通过他们的值来判断他们的数据类型。我们必须要适应Python程序的这种写法。
- elif
elif TempStr[-1] in ['C','c']:
Python语言中含有elif语句,相当于else if
- 字符串的反向递减序号和切片机制
if TempStr[-1] in ['F','f']:
我们看到程序对于字符串TempStr使用了-1这个索引,这是怎么回事呢?
在Python中,字符串同时具有正向递增序号和反向递减序号,我们可以通过其中任意一种序号机制查找我们需要的元素,具体如下图所示。
这样我们就可以理解TempStr[-1]的目的是取字符串TempStr的最后一个字母
C=(eval(TempStr[0:-1])-32)/1.8
我们再来看这段代码中的TempStr[0:-1],这代表了Python中的字符串切片机制。
切片:返回字符串中一段字符子串 格式为<字符串>[M,N]
切片会返回从字符串第M个位置开始到第N-1个位置的字串(注意:不包括第N个位置)
还要注意一点,同大多数编程语言一样,Python中字符串中元素的位置是从0开始计数的。
所以TempStr[0:-1]的意思即为取原字符串去掉最后一个元素所形成的新字符串(不理解的请回顾上面的反向递减序号机制)。
那么我如果想要取到最后一个字符怎么办呢?很简单,只要不写切片的第二个参数就可以了。比如说,TempStr[0:]就代表取原字符串,TempStr[1:]就代表取原字符串去掉第一个字符所形成的新字符串。
- 列表类型
if TempStr[-1] in ['F','f']:
在该行代码中 ['F','f']
是一个列表类型。
列表类型相当于数组类型,但Python中的列表类型有许多强大的函数。比如本局中的in语句,可以快速判断元素是否在列表中。列表类型也支持反向递减序号。
有关列表类型,此处不做过多讨论。
- eval()函数
C=(eval(TempStr[0:-1])-32)/1.8
在这句代码中,有一个我们没见过的eval()函数,它有什么作用呢?
评估函数eval()
——去掉参数最外层引号并执行余下语句的函数
我们来举几个例子看一下它的用法
eval("1")
在这个例子中,参数为"1"
,函数首先去掉最外层引号,参数变为1
,再执行1
,结果为1
,即该语句会返回整数类型1
eval("1+2")
在这个例子中,参数为"1+2"
,函数首先去掉最外层引号,参数变为1+2
,再执行1+2
,结果为3
,即该语句会返回整数类型3
eval('"1+2"')
在这个例子中,参数为'"1+2"'
,函数首先去掉最外层引号,参数变为"1+2"
,再执行"1+2"
,结果为"1+2"
,即该语句会返回字符串类型"1+2"
eval('print("Hello")')
在这个例子中,参数为'print("Hello")'
,函数首先去掉最外层引号,参数变为print("Hello")
,再执行print("Hello")
,程序会输出Hello
这样我们可以回过头来看我们这个程序中的代码
C=(eval(TempStr[0:-1])-32)/1.8
这里的TempStr[0:-1]
根据前面介绍的知识可以推断出是一个字符串类型,一个典型值是"34.56"
,那么此时eval(TempStr[0:-1])
就会返回浮点数类型34.56
- print函数的格式化
print("转换后的温度是{:.2f}C".format(C))
print是输出函数,这行代码中{:.2f}表示将format中的参数C填充到这个位置,.2f表示了填充时只用保留C的小数点后两位。
即本行代码的实际输出为"转换后的温度为"+C(只精确到小数点后两位)+“C”
注意:紧跟在{:.2f}后的那个C是单纯的一个字母C,是字符串的一个元素,而format(C)
中的这个C是上文C=(eval(TempStr[0:-1])-32)/1.8
中的C变量,{:.2f}需要用format(C)
中的C变量填充。
关于这10行Python代码的解释到这里就结束啦!从中我们可以发现Python在简化代码量方面确实相比其他语言有很大改善。
最后补充一点小知识,Python是典型的解释型语言,解释型语言的特征是在执行程序之前不会对程序进行整体的编译而是每当执行到某一句语句时才对其进行”解释执行“。我们可以试一试下面这段代码。
import turtle
turtle.pensize(2)
turtle.circle(10)
turtle.circle(40)
turtle.circle(80)
turtle.circle(160)
这段代码会绘制出几个同切的圆,我们不妨将其中的第5行故意写错,变为
import turtle
turtle.pensize(2)
turtle.circle(10)
turtle.circle(40)
turtel.circle(80)
turtle.circle(160)
再次运行程序,看看程序是怎样执行的?思考一下如果我们使用C++或者java编写类似的程序,会出现相同的效果吗?