3.14 用Python实现的简单加法器
感谢:Brett Cannon
任务
你想用Python制作一个简单的加法器,使用精确的十进制数(而不是二进制浮点数),并以整洁的纵列显示计算结果。
解决方案
为了执行计算,必须使用decimal模块。我们的程序接受输入行,每行由一个数字紧跟一个数学运算符组成,空行表示收到了计算当前结果的请求,输入q则表示结束当前程序:import decimal, re, operator
parse_input=re.compile(r'''(?x) # 允许RE中的注释和空白符
(\d+\.?\d*) # 带有可选的小数部分的数
\s* # 可选的空白符
([-+/*]) # 运算符
$''') # 字符串结束
oper= { '+': operator.add, '-': operator.sub,
'*': operator.mul, '/': operator.truediv,
}
total=decimal.Decimal('0')
def print_total( ):
print '== == =\n', total
print """Welcome to Adding Machine:
Enter a number and operator,
an empty line to see the current subtotal,
or q to quit: """
while True:
try:
tape_line=raw_input( ).strip( )
except EOFError:
tape_line='q'
if not tape_line:
print_total( )
continue
eliftape_line== 'q':
print_total( )
break
try:
num_text,op=parse_input.match(tape_line).groups( )
except AttributeError:
print 'Invalid entry: %r' % tape_line
print 'Enter number and operator,
empty line for total, q to quit'
continue
total=oper[op](total, decimal.Decimal(num_text))
讨论
Python的交互式解释器是很有用的计算器,但一个简单的"加法器"也还是有用的。举个例子,像2345634+2894756-2345823这样的表达式很不易读,所以检查用于计算的输入数字并不像想象的那么简单。而一个简单的加法器可以用一种很整洁的、纵列的方式显示数字,这样可以很容易地多次检查你的输入。另外,decimal模块使用一种基于十进制的计算方式,那也正是我们需要的,我们很多时候并不需要科学家、工程师或计算机所偏爱的浮点数学计算。
当在命令行shell下运行此脚本时(此脚本并不是为在Python交互式解释器中运行而设计的),它会给出使用提示,然后一直等待输入。可以敲入一个数字(一位或者多位数字,加上一个可选的小数点,然后是可选的小数位数字),紧跟一个运算符(/、*、-和+,这4个字符可以在键盘的数字区找到),然后回车。脚本会根据运算符将输入的数计入到总数中。当你输入空行时,程序将打印出当前的计算结果。当输入q并回车时,程序会退出。这种简单的输入输出的界面符合一个典型的简单加法器的需求。
decimal包是Python 2.4标准库的一个组成部分。如果你使用Python 2.3,请访问http://www.taniquetil.com.ar/facundo/bdvfiles/get_decimal.html,下载并安装这个包。decimal可支持高精度的十进制数学运算,相比于二进制浮点运算,它的应用面更加广泛(比如涉及财务的计算),当然浮点运算是计算机上速度最快的运算,也是Python默认的运算方式。你再也无须花费时间和精力去学习难于理解的二进制浮点运算。如3.13节所示,可以将默认的截断规则ROUND_HALF_EVEN按需求修改成其他规则。
本节的代码非常简单,也有很多可以提升性能的地方。一个有用的加强方法是,将外界输入记录到硬盘以备查用。可以简单地做到这一点-只需要在循环之前加一条语句,打开一个文本文件以供添加信息:tapefile=open('tapefile.txt', 'a')
然后,在获得tape_line的值的try/except语句之后,加一条语句以便将值写入文件之中:tapefile.write(tape_line+'\n')
如果做了上面这些操作,也许你还想继续加强print_total函数,使得它既能够输出信息到命令行窗口,同时还能将信息写入到文件中。因此,该函数可以被修改为:def print_total( ):
print '==== =\n', total
tapefile.write('==== =\n' + str(total) + '\n')
file对象的write方法接受一个字符串作为参数,但是并不默认地在字符串末尾加上换行,这和print语句的行为方式有些不同,所以我们要明确地调用内建的str函数,明确地在末尾增加了一个'\n'。***,此版本的print_total函数的第二条语句还可以被改写为:print>>tapefile, '==== =\n', total
有些人非常讨厌这种print >>> somefile的语法,但有时这种写法真的很方便,上面的应用就是一个例子。
还有一些可能的改进,比如现在每次输入完运算符之后都需要按回车键,进一步的改进可以不用按回车就直接进行处理(不过这意味着我们需要处理无缓冲的输入,并且每次要单个处理一个字符,而不能使用方便的基于行的内建函数raw_input,可以参考2.23节提供的一种跨平台的处理无缓冲输入的方法),再比如增加一个clear函数(或者增加提示功能,如果用户输入0*会把结果清空成0),甚至给这个加法器增加一个GUI外壳。不过,我准备把这些部分留给读者作为练习。
本节实现中非常重要的一点是oper字典,它用运算符(/、*、-和+)作为键,用内建的operator模块中的数学运算函数作为键的对应值。这个功能也可以用更冗长一点的方法实现,比如,一长串if/elif,如下:ifop== '+':
totaltotal= total + decimal.Decimal(num_text)
elifop== '-':
totaltotal= total - decimal.Decimal(num_text)
elifop== '*':
... and so on ...
不过,Python的字典用法明显更理想也更方便,而且不会产生重复性的代码,也更容易维护。
更多资料
【责任编辑:云霞 TEL:(010)68476606】
点赞 0