第6章 数量转换
Python编程基础
- 字典
- 字符串操作
- if…elif…else语句
- 递归
前面的输入和输出都是阿拉伯数字,这一章我们来看一下如何实现阿拉伯数字和汉字数字之间的相互转换。
6.1 阿拉伯数字转换成汉字数字
新建一个“数字转换.py”的脚本文件,在文件中输入自定义函数shu_hanzhi的源码:
def shu_hanzi(shu): 批注:
dic_shu = {0:'零',1:'一',2:'二',3:'三',4:'四',5:'五', 函数:shu_hanzi(),
6:'六',7:'七',8:'八',9:'九',10:'十'} 参数为shu(数)
变量:dic_shu(数字映射的字典)
# 获得个位、十位、百位、千位、万位数字
s = [] 变量:s(数字的列表)
while len(s) < 4: 函数:len(),int(),print()
s.append(shu%10) 列表方法append()
shu = int(shu/10) 比较运算符:<(小于)
s.append(shu) 算术运算符:/(除), %(取模)
print(s)
# 转换数字并连接成汉字字符串
hz = "" 变量:hz(汉字字符串),
dw = ['','十','百','千','万'] dw(汉字位数),
i = 0 i(循环计数器)
while i<len(s): 控制流语句:while循环语句
if s[i] != 0: if...else语句
if s[i] >= 10: 比较运算符:<(小于),
hz = shu_hanzi(s[i])+dw[i]+hz !=(不等于)
else: >=(大于等于)
hz = dic_shu[s[i]]+dw[i]+hz 字符串连接运算符:+
i = i+1 算术运算符:+
return hz
6.1.1 程序剖析
我们在这里自定义了一个函数,函数名为“shu_hanzi”,接受的参数是shu(数)。整个函数分3部分。第一部分初始化一个字典dic_shu;第二部分获得个位、十位、百位、千位、万位数字;第三部分转换数字连接成汉字字符串并返回。
1.第一部分
dic_shu = {0:'零',1:'一',2:'二',3:'三',4:'四',5:'五',
6:'六',7:'七',8:'八',9:'九',10:'十'}
字典和列表一样,也是一个值的序列,不同的地方在于:列表的索引默认是从0开始的整数,而字典的索引可以是不能修改的任何类型(例如整数、浮点数、字符串、元组,但不可以是列表,因为列表能被修改)。字典的索引叫做键(key),每个键关联着一个值(value)。一个键和一个值的关联叫做一个键值对或者一个项。例如上面的字典dic_shu中,0:'零'
就是一个键值对,这个键值对中,整数0是键,字符串’零’是值。整个字典使用一对大括号{}框住所有的键值对,各个键值对之间使用逗号“,”分隔,键和值之间使用冒号“:”分隔。
如果用数学语言来表达,一个字典表示从键到值的一个映射,因此我们也可以说每一个键映射到了一个值。字典dic_shu就是把阿拉伯数字映射到汉字数字,键是阿拉伯数字(类型是整数),值是对应的汉字数字(类型是字符串)。我们可以使用键来查找对应的值:
>>> dic_shu={0:'零',1:'一',2:'二',3:'三',4:'四',5:'五',
6:'六',7:'七',8:'八',9:'九',10:'十'}
>>> dic_shu[3]
'三'
>>> dic_shu[10]
'十'
如果键不在字典中,会得到一个异常:
>>> dic_shu[11]
Traceback (most recent call last):
File "<pyshell#2>", line 1, in <module>
dic_shu[11]
KeyError: 11
2.第二部分
# 获得个位、十位、百位、千位、万位数字
s = []
while len(s) < 4:
s.append(shu%10)
shu = int(shu/10)
s.append(shu)
print(s)
函数的第二部分代码解析接收的阿拉伯数字,提取出这个数的个位、十位、百位、千位、万位的数字,并依次存放于列表s中。例如接收的数为159256,代码运行后列表s的值为[6,5,2,9,15],s[0]是个位数字6,s[1]是十位数字5,s[2]是百位数字2,s[3]是千位数字9,s[4]是万位数字15;如接受的数为25,列表s的值为[5,2,0,0,0]。
s=[]首先初始化s为一个空列表。
while len(s) < 4:
s.append(shu%10)
shu = int(shu/10)
这个while语句的条件len(s)<4调用了len()函数,len()函数将返回传递给它的列表中值的个数,假如列表s有3个值,那么len(s)的返回值就是3。这段while语句的意思如下。
当列表s中值的个数小于4时:
取shu除以10 的余数,并把这个余数加入到列表中
取shu除以10的整数部分,将变量shu的值替换成这个整数
第一次循环,余数是个位数字,shu的新值是去除了个位数字的数,如shu是159256,第一次循环后,余数为6,加入列表s,shu更新为15925;以此类推,直到列表s中已有个位、十位、百位、千位的数字。如shu是159256,循环结束后,shu的值为万位数字15。
s.append(shu)将循环结束后剩下的万位数字加入列表s。
print(s)语句只是打印列表s,便于调试和查看,实际运行时,这条语句可以删除。
3.第三部分
图6-1 第三部分代码
函数的第三部分将s列表中的数字转换成汉字数字,并连接成汉字字符串返回,如图6-1所示。
hz=""首先将函数要返回的字符串初始化为空字符串。
dw = [’’,‘十’,‘百’,‘千’,‘万’]对应列表s初始化了一个列表dw(单位)。列表dw的第1个元素对应列表s的第1个元素(个位数字),为空字符串;第2个元素对应列表s的第2个元素(十位数字),为字符串‘十’;以此类推。
i = 0将一个变量i初始化为0,这个变量是个计数器,用来控制后面的while循环。
这个while语句的意思如下。
当变量i的值小于列表s中值的个数时,执行以下操作:
如果列表s索引为i的值不等于0的话:
如果列表s索引为i的值大于等于10的话:
调用函数shu_hanzi()处理列表s中的这个值,返回的字符串连接列表
dw索引为i的值,再连接变量hz的值,形成一个新的字符串赋值于变量hz
否则:
取dic_shu中键为列表s索引为i的值的值,连接列表dw索引为i的值,再连接变量hz的值,形成一个新的字符串赋值于变量hz
变量i的值加1
这个while语句中有一个嵌套的if语句,在内层的if子句中还调用了自定义函数shu_hanzi本身,也就是说自己调用自己,这称为递归,看起来有点复杂,我们可以通过在纸上运行它来帮助理解,这也是一种阅读代码的方式。
假设自定义函数shu_hanzi()传入的参数为159256,在第一部分、第二部分代码运行完成后,列表s的值为[6,5,2,9,15],值的个数为5。计数器i初始为0,每次循环加1,直至等于列表s值的个数5,才结束循环,也就是说,循环要执行5次。
第一次循环:
表6-1 shu_hanzi(159256)第一次循环
I | s[i] | dw[i] | dic_shu[s[i]] | hz |
---|---|---|---|---|
0 | s[0] | dw[0] | dic_shu[s[0]] | ‘’ |
6 | ‘’ | dic_shu[6] | ||
‘六’ |
s[0]不等于0,所以执行外层的if子句,但是s[0]小于10,所以执行内层if…else语句的else子句,即执行语句hz = dic_shu[s[i]]+dw[i]+hz;由表6-1可知,右边表达式求值如下:
dic_shu[s[i]]+dw[i]+hz →‘六’+’’+’’→‘六’
i的值加 1,更新为1;hz被赋值更新为‘六’;
第二次循环:
表6-2 shu_hanzi(159256)第二次循环
i | s[i] | dw[i] | dic_shu[s[i]] | hz |
---|---|---|---|---|
1 | s[1] | dw[1] | dic_shu[s[1]] | ‘六’ |
5 | ‘十’ | dic_shu[5] | ||
‘五’ |
s[1]不等于0,所以执行外层的if子句,但是s[1]小于10,所以执行内层if语句的else子句,即执行语句hz = dic_shu[s[i]]+dw[i]+hz;由表62可知,右边表达式求值如下:
dic_shu[s[i]]+dw[i]+hz →‘五’+’十’+’六’→‘五十六’
i的值加 1,更新为2;hz被赋值更新为‘五十六’;
第三次循环:
表6-3 shu_hanzi(159256)第三次循环
i | s[i] | dw[i] | dic_shu[s[i]] | hz |
---|---|---|---|---|
2 | s[2] | dw[2] | dic_shu[s[2]] | ‘五十六’ |
2 | ‘百’ | dic_shu[2] | ||
‘二’ |
s[2]不等于0,所以执行外层的if子句,但是s[2]小于10,所以执行内层if语句的else子句,即执行语句hz = dic_shu[s[i]]+dw[i]+hz;由表6-3可知,右边表达式求值如下:
dic_shu[s[i]]+dw[i]+hz →‘二’+’百’+’五十六’→‘二百五十六’
i的值加 1,更新为3;hz的值被更新为‘二百五十六’;
第四次循环:
表6-4 shu_hanzi(159256)第四次循环
i | s[i] | dw[i] | dic_shu[s[i]] | hz |
---|---|---|---|---|
3 | s[3] | dw[3] | dic_shu[s[3]] | ‘二百五十六’ |
9 | ‘千’ | dic_shu[9] | ||
‘九’ |
s[3]不等于0,所以执行外层的if子句,但是s[3]小于10,所以执行内层if语句的else子句,即执行语句hz = dic_shu[s[i]]+dw[i]+hz;由表6-4可知,右边表达式求值如下:
dic_shu[s[i]]+dw[i]+hz →‘九’+’千’+’二百五十六’→‘九千二百五十六’
i的值加 1,更新为4;hz的值被更新为‘九千二百五十六’;
第五次循环:
表6-5 shu_hanzi(159256)第五次循环
I | s[i] | dw[i] | shu_hanzhi(s[i]) | hz |
---|---|---|---|---|
4 | s[4] | dw[4] | shu_hanzhi(s[4]) | ‘九千二百五十六’ |
15 | ‘万’ | shu_hanzhi(15) | ||
‘一十五’ |
s[4]不等于0,所以执行外层的if子句,但是s[4]大于10,所以执行内层if语句的if子句,即执行语句hz = shu_hanzhi(s[i])+dw[i]+hz;这条语句中调用了函数shu_hanzhi(),也就是定义的这个函数的本身,自己调用自己叫做递归,在这里传递给函数的参数是s[4],即15,如表6-5所示。
调用运行shu_hanzi(15),过程如下:
初始化字典dic_shu
获得数15的个位和十位数字,列表s为[5,1,0,0,0]
初始化hz,dw
初始化i为0
shu_hanzi(15)第一次循环:
表6-6 shu_hanzi(15)第一次循环
i | s[i] | dw[i] | dic_shu[s[i]] | hz |
---|---|---|---|---|
0 | s[0] | dw[0] | dic_shu[s[0]] | ‘’ |
5 | ‘’ | dic_shu[5] | ||
‘五’ |
s[0]不等于0,所以执行外层的if子句,但是s[0]小于10,所以执行内层if语句的else子句,即执行语句hz = dic_shu[s[i]]+dw[i]+hz;由表6-6可知,右边表达式求值如下:
dic_shu[s[i]]+dw[i]+hz →‘五’+’’+’’→‘五’
i的值加 1,更新为1;hz被赋值更新为‘五’;
shu_hanzi(15)第二次循环:
表6-7 shu_hanzi(15)第二次循环
i | s[i] | dw[i] | dic_shu[s[i]] | hz |
---|---|---|---|---|
1 | s[1] | dw[1] | dic_shu[s[1]] | ‘五’ |
1 | ‘十’ | dic_shu[1] | ||
‘一’ |
s[1]不等于0,所以执行外层的if子句,但是s[1]小于10,所以执行内层if语句的else子句,即执行语句hz = dic_shu[s[i]]+dw[i]+hz;由表6-7可知,右边表达式求值如下:
dic_shu[s[i]]+dw[i]+hz →‘一’+’十’+’五’→‘一十五’
i的值加 1,更新为2;hz被赋值更新为‘一十五’;
shu_hanzi(15)第三次循环:
i = 2,s[i] = s[2] = 0,hz =‘一十五’
s[2]等于0,所以不执行外层的if子句,也就不执行内层if语句。
i的值加 1,更新为3;hz的值不变,仍为‘一十五’;
shu_hanzi(15)第四次循环:
i = 3,s[i] = s[3] = 0,hz =‘一十五’
s[3]也等于0,所以同上不执行if语句。
i的值加 1,更新为4;hz的值不变,仍为‘一十五’;
shu_hanzi(15)第五次循环:
i = 4,s[i] = s[4] = 0,hz =‘一十五’
s[4]也等于0,所以同上不执行if语句。
i的值加 1,更新为5;hz的值不变,仍为‘一十五’;
循环结束,return hz 返回结果‘一十五’
程序运行返回到外层第五次循环,执行语句hz = shu_hanzi(s[i])+dw[i]+hz,右边表达式求值如下:
shu_hanzi(s[i])+dw[i]+hz →‘一十五’+’万’+’九千二百五十六’→‘一十五万九千二百五十六’
i的值加 1,更新为5;hz被赋值更新为‘一十五万九千二百五十六’;
循环结束。
所以,当列表s的值为[6,5,2,9,15],函数第三部分代码返回的结果是‘一十五万九千二百五十六’。
在这里,我们可以看到shu_hanzi(159256)和它所调用的shu_hanzi(15)里的变量名全都相同,但实际运行时,这些变量是不同的。函数shu_hanzi(15)被调用时,会创建一个专有的空间(也就是局部作用域)。在函数内被赋值的所有变量,都存在于这个空间内。当函数返回时,这个空间就会被销毁,其中的变量会丢失,不会影响外层同名的变量,如图6-2所示。
图6-2 函数局部作用域
6.1.2 运行结果
我们可以在“数字转换.py”脚本文件中的末尾输入语句print(shu_hanzi(159256)),调用前面所定义的函数shu_hanzi(),把阿拉伯数字159256转换成汉字数字。按F5快捷键运行脚本,运行结果如图6-3所示。
图6-3 shu_hanzi(159256)函数运行结果
结果中显示的第1个列表[6, 5, 2, 9, 15]是shu_hanzi(159256)解析数字159256时形成的列表,而第2个列表[5, 1, 0, 0, 0],是递归调用shu_hanzi(15),解析万位数字15时形成的列表,最终结果‘一十五万九千二百五十六’。
6.2 汉字数字转换成阿拉伯数字
在“数字转换.py”的脚本文件中输入自定义函数hanzhi_shu的源码:
def hanzi_shu(hz): 批注:
dic_hanzi={"一":1,"二":2,"三":3,"四":4,"五":5, 变量:dic_hanzi(数字映射的字典)
"六":6,"七":7,"八":8,"九":9,"十":10}
s=[0,0,0,0,0] s(存放各位数字的列表)
# 获取万位数字并转换
if "万" in hz: 控制流语句:if...elif...else
i = hz.index("万") 变量:i(位置的索引号)
sz= hz[:i] sz(截取的数字字符串)
if len(sz) == 1: 函数:index(),len()
s[0]=dic_hanzi[sz] 比较运算符:==(等于)
elif len(sz) == 0:
s[0]=dic_hanzi["一"]
else:
s[0]=hanzi_shu(sz)
if i+1 == len(hz):
hz=''
else:
hz=hz[i+1:]
# 获取千位数字并转换
if "千" in hz:
i = hz.index("千")
sz= hz[:i]
if len(sz) == 0:
s[1]=dic_hanzi["一"]
else:
s[1]=dic_hanzi[sz]
if i+1 == len(hz):
hz=''
else:
hz=hz[i+1:]
# 获取百位数字并转换
if "百" in hz:
i = hz.index("百")
sz= hz[:i]
if len(sz) == 0:
s[2]=dic_hanzi["一"]
else:
s[2]=dic_hanzi[sz]
if i+1 == len(hz):
hz=''
else:
hz=hz[i+1:]
# 获取十位数字并转换
if "十" in hz:
i = hz.index("十")
sz= hz[:i]
if len(sz) == 0:
s[3]=dic_hanzi["一"]
else:
s[3]=dic_hanzi[sz]
if i+1 == len(hz):
hz=''
else:
hz=hz[i+1:]
# 转换个位数字
if len(hz) != 0: 比较运算符:!=(不等于)
s[4]=dic_hanzi[hz]
# 万位、千位、百位、十位、个位合成一个完整的数并返回
shu = s[0]*10000+s[1]*1000+s[2]*100+s[3]*10+s[4] 算术运算符:*(乘),+(加)
return shu
6.2.1 程序剖析
我们同样自定义了一个函数hanzi_shu(),接受的参数为hz(汉字字符串)。整个函数分7部分。第一部分初始化两个变量,第二部分获取万位数字并转换,第三部分获取千位数字并转换,第四部分获取百位数字并转换,第五部分获取十位数字并转换,第六部分转换个位数字,第七部分将万位、千位、百位、十位、个位合成一个完整的数并返回。
1.第一部分
dic_hanzi={"一":1,"二":2,"三":3,"四":4,"五":5,
"六":6,"七":7,"八":8,"九":9,"十":10}
s=[0,0,0,0,0]
第一部分初始化了两个变量dic_hanzi和s。
dic_hanzi是一个字典,将汉字数字映射到阿拉伯数字上,键是汉字数字(类型是字符串),值是对应的阿拉伯数字(类型是整数)。
s是一个列表,初始化为5个整数0,第1个元素表示万位,第2个元素表示千位,第3个元素表示百位,第4个元素表示十位,第5个元素表示个位。
2.第二部分
图6-4 第二部分代码
译:
如果hz(汉字字符串)中有“万”字:
找到“万”字在hz中的位置,赋值于变量i
取出hz中“万”字之前的汉字,赋值于变量sz
如果sz的长度等于1(“万”字前有一个汉字):
取出dic_hanzi中键为sz的值,赋值于s的第1个元素
否则如果sz的长度等于0(“万”字前没有汉字):
取出dic_hanzi中键为“一”的值,赋值于s的第1个元素
否则:(“万”字前有一个以上汉字):
递归调用函数hanzi_shu(),返回结果赋值于s的第1个元素
如果 hz中“万”字后没有汉字:
hz赋值为空字符串
否则:
取出hz中“万”字之后的汉字,赋值于hz(也就是说,删
除hz中“万”字之前的汉字,包括“万”字)
这段代码是一个if语句,if语句里嵌套了一个if…elif…else语句和一个if…else语句。代码主要是对字符串hz进行操作。可以将字符串看成是一个列表,例如’Hello world!'字符串中的每个字符都是一个表项,有对应的下标,如图6-5所示。
图6-5 字符串对应的下标
所以,字符串可以使用列表的很多操作。
in操作符:可以使用in操作符来判断某特定值是否存在于列表中;not in来判断某特定值是否不存在于列表中。上面的语句if
"万"in hz
的条件,就是判断“万”字是否存在于字符串hz中,如果存在返回True,不存在返回False。
index()方法:index是一个列表方法,用于从列表中找出某个值第1个匹配元素的索引位置。hz.index(“万”)就是从字符串hz中找出第1个“万”字的索引位置,假设hz为’一十五万九千二百五十六’,该字符串对应的下标如图6-6所示。
第1个
图6-6 字符串对应的下标
那么,第1个“万”字的索引位置就是3,hz.index(“万”)返回结果3。
方法和函数是两个不同的概念,两者之间的区别会在下篇中讲到。
利用切片取得子列表:使用0、1这样的下标可以从列表中取得单个的元素,而“切片”则可以从列表中取得多个元素。切片的结果是一个新的列表。“切片”和下标一样,写在一对方括号中,和下标不同的是,“切片”有两个冒号分隔的整数。在一个“切片”中,第1个整数是“切片”开始处的下标。第2个整数是“切片”结束处的下标。例如:
>>> s = ['a','b','c','d','e']
>>> s[1:3]
['b', 'c']
>>> s[0:4]
['a', 'b', 'c', 'd']
s[1:3]表示切取列表s的第2个元素到第4个元素之间的部分,也就是第2个元素和第3个元素(不包括第4个元素)。s[0:4]表示切取列表s的第1个元素到第5个元素之间的部分(不包括第5个元素)。
你可以省略切片中冒号两边的一个下标或两个下标。省略第1个下标相当于使用 0,也就是从列表的第1个元素开始。省略第2个下标意味着分片直至列表的末尾。例如:
>>> s[:4]
['a', 'b', 'c', 'd']
>>> s[1:]
['b', 'c', 'd', 'e']
>>> s[:]
['a', 'b', 'c', 'd', 'e']
s[:4]等同于s[0:4],s[1:]取列表s的第2个元素到列表末尾的部分。s[:]则是取列表s从开始到末尾的所有元素。
所以,当hz为’一十五万九千二百五十六’时,i = hz.index(“万”)语句找到“万”字在hz中的位置3,赋值i为3;sz= hz[:i]即为sz= hz[:3],hz[:3]取出hz的第1个元素到第4个元素之间的部分(不包括第4个元素),即’一十五’,也就是取出了hz中“万”字之前的汉字,即万位数字。这个万位数字’一十五’赋值给了变量sz。
if…elif…else语句:前面我们接触过if语句,if…else语句,这儿的语句中间多了个elif。elif 语句是“否则如果”,总是跟在 if 或另一条 elif 语句后面。它提供了另一个条件,仅在前面if语句或elif语句的条件为 False 时才检查该条件。
elif 语句总是包含以下部分:
- elif 关键字;
- 条件(即求值为 True 或 False 的表达式);
- 冒号“:”;
- elif 子句:下一行开始,缩进的代码块。缩进需对齐。
这段代码中的if…elif…else语句实现万位数字的转换。当万位数字为一个字,例如‘五’时,s[0]=dic_hanzi[sz]从字典dic_hanzi中取出键为‘五’的值5,赋值给列表s的第1个元素;当万位数字为空,那么默认前面是‘一’,从字典dic_hanzi中取出键为‘一’的值1,赋值给列表s的第1个元素;当万位数字有两个字以上,递归自调用函数hanzi_shu(),假设万位数字为’一十五’,那么递归调用函数hanzi_shu(’一十五’),函数运行结果赋值给列表s的第1个元素。这个递归函数的运行会在后面再讲到。
len()函数:这段代码的最后一个if…else语句在字符串hz中删除了“万”字以前的汉字(包括“万”字)。在字符串上运用了len()函数,len()函数可用来返回序列对象(如列表、字符串、元组、字典)中元素的个数。
在条件i+1 == len(hz)中,i是“万”字在字符串hz中的索引位置,若hz为’一十五万’,i为3,i+1就是“万”字后的位置4;len(hz)返回字符串hz中元素(字符)的个数,也为4;条件i+1 == len(hz)为True也就意味着:hz中“万”字后面没有汉字。如果这样,删除“万”字以前的汉字(包括“万”字)后,hz就是空字符串,所以,hz=’’。
如果hz中“万”字后面有汉字,也就是条件i+1 == len(hz)为False时,那么,需要对hz进行切片操作,截取“万”字后面的汉字。假设hz为’一十五万九千二百五十六’,那么hz[i+1:]即为hz[4:],求值为‘九千二百五十六’,这个值赋值给hz,hz更新为‘九千二百五十六’,也就是,删除了“万”字以前的汉字(包括“万”字)。
3.第三部分
第三部分代码用于获取千位数字并转换,程序逻辑与第二部分类同。假设hz为‘九千二百五十六’:
- 首先,找出字符串hz中“千”字的位置1,赋值给i;
- 接着,使用切片操作hz[:i],取出hz中“千”字之前的汉字‘九’,赋值给变量sz;
- 接着,一个if…else语句用来实现千位数字的转换,如果千位数字为空,也就是len(sz) == 0,那么默认前面是‘一’,s[1]=dic_hanzi[“一”]从字典dic_hanzi中取出键为‘一’的值1,赋值给列表s的第2个元素;否则,s[1]=dic_hanzi[sz]从字典dic_hanzi中取出键为sz的值即9,赋值给列表s的第2个元素。这里没有第二部分的elif语句,这是由于在hz中,出现在“千”字之前的汉字,不会有二个,所以只会出现两种情况:0个或1个。
- 最后,一个if…else语句,用来在字符串hz中删除“千”字以前的汉字(包括“千”字),之后,hz更新为‘二百五十六’。
4.第四部分
第四部分代码用于获取百位数字并转换,程序逻辑与第三部分相同。假设hz为‘二百五十六’,代码运行后,列表s的第3个元素即百位数字为2,hz更新为‘五十六’。
5.第五部分
第五部分代码用于获取十位数字并转换,程序逻辑与第四部分相同。假设hz为‘五十六’,代码运行后,列表s的第4个元素即十位数字为5,hz更新为‘六’。
6.第六部分
# 转换个位数字
if len(hz) != 0:
s[4]=dic_hanzi[hz]
如果前面的代码运行后,字符串hz中还有字符,也就是len(hz) != 0,则余下的这个字符就是个位数字,前面的例子就是‘六’。s[4]=dic_hanzi[hz]从字典dic_hanzi中取出键为‘六’的值6,赋值给列表s的第5个元素。
7.第七部分
# 万位、千位、百位、十位、个位合成一个完整的数并返回
shu = s[0]*10000+s[1]*1000+s[2]*100+s[3]*10+s[4]
return shu
这段代码将列表s中的万位数字、千位数字、百位数字、十位数字和个位数字相加,形成一个完整的数并返回。假设s为[1,2,5,7,0],
s[0]*10000+s[1]*1000+s[2]*100+s[3]*10+s[4] → 1*10000+2*1000+5*100+7*10+0 → 12570
shu被赋值为12570并返回。
6.2.2 运行结果
我们可以在“数字转换.py”脚本文件的末尾输入语句print(hanzi_shu(‘一十五万九千二百五十六’)),调用前面所定义的函数hanzi_shu(),把汉字数字’一十五万九千二百五十六’转换成阿拉伯数字。为了方便调试,可以在第七部分代码前添加语句print(s),用来打印列表s的值。按F5快捷键运行脚本,运行结果如图6-7所示。
图6-7 hanzi_shu(‘一十五万九千二百五十六’)运行结果
运行结果里显示有两个列表,这是怎么回事呢?这是因为在处理万位数字时,递归调用了函数hanzi_shu()。程序的运行顺序如下:
hanzi_shu(‘一十五万九千二百五十六’)
取出万位数字为‘一十五’
调用函数hanzi_shu('一十五’)
无万位数字,s[0]为0
无千位数字,s[1]为0
无百位数字,s[2]为0
取十位数字‘一’,转换成1,s[3]为1;'一十五’删除‘十’前汉字(包
括‘十’)
余个位数字‘五’,转换成5,s[4]为5
打印列表[0,0,0,1,5]
shu=0*10000+0*1000+0*100+1*10+5=15
返回15
万位数字转换成15,s[0]为15;'一十五万九千二百五十六’截取为‘九千二百五十六’
取千位数字转换成9,s[1]为9;‘九千二百五十六’截取为‘二百五十六’
取百位数字转换成2,s[2]为2;‘二百五十六’截取为‘五十六’
取十位数字转换成5,s[3]为5;‘五十六’截取为‘六’
余个位数字‘六’,转换成6,s[4]为6
打印列表[15,9,2,5,6]
shu=15*10000+9*1000+2*100+5*10+6=159256
返回159256
在这里,我们可以看到hanzi_shu(‘一十五万九千二百五十六’)和它所调用的hanzi_shu('一十五’)里的变量名都是相同的,但实际运行时,这些变量是不同的。函数hanzi_shu('一十五’)被调用时,会创建一个局部作用域。在函数内被赋值的所有变量,都存在于该局部作用域内。函数返回时,这个局部作用域就会被销毁,其中的变量会丢失,不会影响到外层同名的变量,如图6-8所示。
图6-8 函数局部作用域
6.3 练一练
我们可以看到hanzi_shu()函数中的第三部分(取千位数字)、第四部分(取百位数字)、第四部分(取十位数字)中有很多重复的代码,这些重复的代码可以提取出来定义一个新的函数,以简化程序,这也是一种编程的方式,首先写出程序的逻辑,然后提炼出重复的代码,简化程序。