3.2 数字
数字,是任何高级语言都不可缺少的东西,而且任何高级语言都支持数字的计算。Python中的数字也是最基本的对象之一,所以它是本教程中研究的第一个对象。
3.2.1 整数
数学中的整数我们都熟悉了,那么,在Python中如何表示整数(integer)呢?
进入到Python 交互模式中,输入以下内容。
在数学中,3是属于“整数”类型中的一个数字。那么,在Python中,3是什么类型中的数字呢?可以用type(3)这种方式来查看(见图3-2-1)。<class 'int'>是type(3)的返回值,表明数字3的类型是int,即integer(整数)。也就是说,在Python中有一种对象类型称为整数(或者“整数型”),用符号表示就是int。数学中学过的整数3就是这种类型中的一个对象。
图3-2-1 分解type(3)的使用方式
使用不完全归纳方法,得到这样的结论:数学中的所有整数值在Python中都是整数类型(int)。
注意,读者在阅读其他文献的时候,或许会遇到“长整数型”的说法,即较大的整数。在现在Python版本中已经取消了这种类型,统一命名为“整数型”。
刚才使用的type函数在Python中被称为“内置函数”,本章讨论的是“内置对象”。所谓“内置”,就是当Python环境配置好后,相应的东西本地计算机已经有了。所有“内置”的在Python中都可以直接使用,不需要开发者来定义。比如“内置函数”,开发者只需了解函数的使用方法即可,不需要定义这类函数。
那么,如何了解“内置函数”的使用方法呢?
3.2.2 查看文档
“内置函数”(built-in functions)的所有使用方法都在Python帮助文档中——帮助文档中不仅包含“内置函数”,还包含其他帮助内容。
阅读Python帮助文档的方法有两种。一种是访问官方网站,通过网站查看官方文档(见图3-2-2),进入到https://docs.python.org/3/library/functions.html页面,可以看到Python所有内置函数以及该函数的使用文档(见图3-2-3)。
除了看在线文档,还可以看本地的帮助文档。实现这个操作要用另一个内置函数help。
在Python交互模式下这样输入,然后按Enter键,显示图3-2-4所示的内容(屏幕上显示的部分内容)。
图3-2-2 由官方网站进入帮助文档
图3-2-3 Python内置函数帮助文档界面
图3-2-4 type函数的部分帮助文档内容
显然,这是一种简单的方法,特别推荐使用。
本节只研究type(object) -> the object's type,其他使用方法暂存。
❖ type:函数名,后面紧跟“( )”。
❖ object:表示参数是一个对象。
❖ -> the object's type:表示这个函数的返回值是对象的类型。
当阅读完文档内容,按键盘上的q键,就可以退回到交互模式中。
help函数是研习Python经常用到的一种方式,用来查看联机文档非常方便。请读者习惯使用,并能够耐心阅读文档。
3.2.3 浮点数
对于数字,除了“整数”,还有“小数”,在Python中怎么表示呢?
进入到Python 的交互模式中,按照下面的方式操作。
在Python 中写“小数”与在数学中的表现形式一样,如果查看它的类型,返回值不是“decimal”(小数),而是“float”(翻译为“浮点数”)。其实不仅是Python,很多高级语言都是如此。但是不能把小数都称为“浮点数”,因为还有“定点数”。显然,“浮(动)”和“(固)定”是相反的。关于“定点数”和“浮点数”的详细内容,建议读者自行查阅有关资料进行学习,此处不详述。
至此,我们已经学习了两种内置对象类型:整数和浮点数。注意,在用type函数查看数字所属类型的时候,返回值的完整形式是“<class'int'>”或“<class'float'>”,其中class也有其他含义,第6章将对此阐述。读者姑且知道“int和float既是对象又是对象类型”。
观察上面的操作,能得到什么结论?
❖ 观察1:int函数实现了把浮点数转化为整数的作用,并且是截取整数,而不是四舍五入。
❖ 观察2:float函数实现了把整数转化为浮点数的作用。
浮点数类型的对象3.0和整数类型的对象3是同一个数吗?上面这种提问,在数学中或许容易回答,但是在Python中就没那么简单了。两个分属于不同类型的对象能一样吗?比如,属于“动物”类型的“张三”(此姓名纯属虚构,如有雷同实属巧合)和属于“植物”类型的“香樟树”肯定不一样。以此类推,“3”和“3.0”应该不是同一个数了。
Python中,两个对象是否为“同一个”有严格的判断标准,就是看它们的内存地址是否相同——每个对象,在计算机内存中都会有相应的地址编号。查看对象内存地址的方式是使用内置函数id。请读者在交互模式中使用help(id)查看此函数帮助文档。
id函数的返回值是参数对象的内存地址。如上面操作所示,两个对象的内存地址不同,则说明它们是不同的对象。
综上所述:int和float除了表示类型和类别,还能够实现对象的类型转化。
当然,对象的类型转化是有条件的,不是任何类型的对象都能够进行转化。
3.2.4 变量
数学中已经熟悉了“变量”这个名词,在Python中同样需要“变量”。Python中的变量(variable)不是孤立存在的,而是依附在对象上的。例如:
在“x=5”中,x是变量,5是整数类型的对象,通过“=”把x和5建立了一种关系。
这里依然是变量x,它又与浮点数类型的对象“6.3”建立了关系。
以上操作过程中,并没有规定变量x必须跟什么类型的对象建立关系,也没有规定变量x是什么类型,而是想要让变量与某个对象建立关系,就使用“=”实现关系的建立。这样的关系被称为“引用”,即可以表述为变量x与对象5(或者对象6.3)建立了“引用关系”。
发挥个人的想象力,形象地理解这种引用关系。把“对象”想象成某个实在的物体,而变量就是一枚标签,这枚标签可以贴到这个对象(物体)上(如x=5),也可以随时取下来贴到另一个对象(物体)上(如同换成了x=6.3)。
这样来看,标签就不需要有什么类型之分了,只要有不同的名字即可。如同上面所完成的操作那样,没有给变量x规定为某种对象类型。这就应了Python中一个重要的观点:对象有类型,变量无类型。
变量没有类型,它也不能被称为对象,所以无法独立存在。
变量必须引用一个对象,才有存在的意义。不然它不被Python认可,就会显示一种名为NameError的错误类型。
当变量引用了对象之后,变量就代表了那个对象。
变量x虽然是对象“6.3”的代表,但是这个代表也有不牢靠的时候。当它代表了其他对象(与其他对象建立了引用关系)时,这里的“6.3”就成为“没有代表”的对象了,会被Python认为是垃圾,并自动回收。
在数学中,通常习惯用x、y之类的单个字符表示变量。但是在高级语言编程中,这样的变量不受欢迎。Python中对变量(严格说是普通变量)命名的基本规则如下:
❖ 变量名称由小写字母、数字和下划线组成,且不以数字开头。
❖ 不使用保留字(关键字)。
❖ 单词之间用单个下划线连接。
❖ 使用有意义的单词。
命名规则中提到了“保留字(关键字)”,怎么知道Python有哪些保留字呢?
在交互模式中执行下面的操作:
可以先不用理解操作的意义,重点看得到的返回值,里面所有的单词都是Python的保留字,请在命名变量时,不要使用这些保留字。
【例题3-2-1】 通过操作,确认哪些变量命名合法。
代码示例:
不合法的变量命名会被显示SyntaxError错误。
3.2.5 简单的计算
有了数字,就可以利用这些数字做简单的运算了,如数学中常见的加、减、乘、除四则运算。
注意观察这种写法,在“a=10”与“b=2.5”之间用英文状态下的“;”分割,其效果等价于下面的写法。
下面让变量a和b代表它们各自引用的对象参与运算。
注意,所有的运算符号都是英文状态下输入的,特别是乘号不要写成“×”。
Python中的除法比上面三种运算稍复杂,表示相除的符号是英文状态的“/”。进入Python交互模式后,练习下面的运算:
除了可以使用“/”符号进行除法运算,还可以使用“//”符号得到两个数相除的商。
“商”肯定是一个整数,并且这个整数不是“/”操作之后得到的结果进行四舍五入(2.5四舍五入后结果是3),通俗地说是“取整”。两个数字相除,除了“商”,还有“余数”,在Python中也提供了计算余数的符号。
除了运算符号,内置函数divmod能够同时获得商和余数。
在Python中,数字之间的加、减、乘、除运算与数学中的四则运算的规则是一样的。
除了四则运算,Python也提供了其他简单运算的方式。比如:
虽然Python(也可以说是计算机)擅长计算,但是有时候会遇到看似难以理解的现象。
这几个简单的运算为什么不能得到精确的结果呢?原因在于十进制数和二进制数的转换。计算机用二进制数进行计算,但在上面的例子中输入的是十进制数,所以计算机需要把十进制的数转化为二进制数,再进行计算。但是,在将类似0.1这样的浮点数转化为二进制数时,有时候就出现问题了。
0.1转化为二进制是:0.0001100110011001100110011001100110011001100110011…
0.1转化为二进制数后,不会精确等于十进制数的0.1。同时,计算机存储的位数是有限制的,所以出现了上述现象。
这种问题不仅在Python中会遇到,在所有支持浮点数运算的编程语言中都会遇到,这不是Python的Bug。
明白了这种问题产生的原因后,该怎么解决呢?就Python的浮点数运算而言,大多数计算机每次计算误差不超过1/253。对于大多数任务来说,这已经足够了,但是要谨记,这不是十进制算法,每个浮点数计算可能带来一个新的舍入错误。
一般情况下,只要简单地将最终显示的结果“四舍五入”到所期望的十进制位数,就会得到满意的最终结果。
实现“四舍五入”可以使用内置函数round,如图3-2-5所示。在Python交互模式下,可以通过help(round)来获取完整的函数帮助文档内容。
图3-2-5 round()函数使用方法示意
但是,round()函数也不能幸免于十进制和二进制转化的问题。
这类问题的彻底解决还有赖于其他工具。请见3.2.7节的相关内容。
在数学上,经常用科学计数法表示一些比较大的数字,如12000写作1.2×104。在Python中也可以使用科学计数法,只不过写法有区别。
1.2e4即表示1.2×104。
【例题3-2-2】 鸡兔同笼,头35个,脚94只,问鸡、兔各多少?
代码示例
3.2.6 math标准库
在数值运算中,除了前面的简单运算,还有如计算对数、正弦、余弦等初等函数的各种运算。但是在Python的内置函数中没有这些函数。
因为这些初等函数也是常用的,所以Python提供了标准库来满足需要。Python标准库是随Python附带安装的,包含很多常用的模块(关于“模块”,请见第7章),此处要使用的math就是标准库中的一个模块。
这里显示出了math模块提供的所有函数。可以使用help函数查看联机帮助文档。
例如,计算数学表达式sin+lg5e2,并且结果保留2位小数。
应用math模块,再结合前面已学和基本的初等数学知识,就能够完成大多数初等数学的运算了。尽管如此,运算中还存在一些问题尚待解决。比如:
还有,前面提到的十进制和二进制转化引起的计算结果不精确问题。所以,必须需要其他工具。
3.2.7 解决“异常”
前面使用标准库中的math模块解决了初等数学的函数问题,为了满足运算的其他要求,Python标准库中还有其他计算相关的模块。比如,decimal实现了十进制数精确运算。
类似“10/3”的计算可以使用标准库中的fractions模块,实现基于有理数的运算。
上述计算结果虽然不是浮点数和整数类型,但是依然能够参与数学运算。
注意,下面的方式是不支持的。
关于计算,Python中能够使用的工具也不仅限于本书介绍的这些,还有诸如NumPy、SciPy等科学计算的专门工具。
【例题3-2-3】 假设两个人,一个人的质量是70kg,另一个人的质量是50kg,当两人相距0.5米的时候,它们之间的引力大小是多少?(G=6.67×10-11m3kg-1s-2)
代码示例
计算表明,这两个人之间的引力大小是9.3×10-7N,仅相当于大约0.095毫克的物体的重力。
本来,数学中的数字没有最大值,但是因为计算机本身的结构问题,在编程语言中的数字不是无限大的。
3.2.8 溢出
正如读者已知,计算机在计算的时候要把十进制的数值转化为二进制的。比如:
在有的语言中,整数有位数的限制,如C语言中26位的短整型、32位的长整型等。在这种情况下,如果计算结果超出了给定位数表示的数值范围,就出现了“整数溢出”的现象。而Python中没有位数的限制,或者说Python中的整数是任意精度,所以可以表示任意大的整数了(仅受制于内存)。
请读者自己调试,显示变量a所引用的数字,它是一个3011位的整数。
但是,如果遇到了浮点数参与运算,则要小心“浮点数溢出”了。
【例题3-2-4】 “夜黑佯谬”,又称为“奥尔伯斯佯谬”,是由德国天文学家奥尔伯斯于1823年提出的,其主要结论是“晚上应该是光亮的而不是黑暗的”。因为计算表明,不论白天和晚上,地球上任何一点得到的来自宇宙中恒星的亮度都是无穷大。不过,这个结论并不符合观察的事实,我们看到的夜空是黑暗的,所以奥尔伯斯宣布这是一个需要解决的佯谬。(更详细的内容请阅读http://blog.sciencenet.cn/blog-677221-921097.html)
这里涉及了“无穷大”,在数学中用符号∞表示,在Python中如何表示?
代码示例
3.2.9 运算优先级
从小学数学开始,就研究运算优先级的问题,如四则运算中的“先乘除,后加减”说明乘法、除法的优先级要高于加减法。同一级别的运算按照“从左到右”的顺序进行计算。
表3-2-1列出了Python 中的各种运算的优先级顺序。
表3-2-1 运算符的优先级
表3-2-1按照优先级从低到高的顺序列出了Python中的常用运算符。虽然有很多还不知道是怎么回事,不过此处先列出来,等以后用到的时候可以回来查看。当然,不需要记忆,因为与数学中的规则完全一样。在复杂的表达式中,使用括号能够让表达式的可读性更强。
在程序中,可读性是非常重要的。
3.2.10 一个简单的程序
在2.2.5节中已经写过了一个简单的程序(文件hello.py)。至今已经学习过一些数值计算了,就可以把程序写得比hello.py复杂一些了。
【例题3-2-5】 已知两个力,F1=20N,F2=10N,这两个力的方向夹角是60°,计算两个力的合力大小和方向。
解题思路
用中学物理知识解决这个问题,即将两个力放到一个直角坐标系中,利用正交分解法进行计算。
代码示例
这段程序的开始部分用三对单引号(或者用三对双引号)包裹着一些文字,这些内容是对本程序文件的说明(简称“程序文档”),在执行这个程序文件的时候,计算机忽略它。程序文档之后的各行语句才是计算机要执行的内容。
因为每行语句的含义都是前述各节知识所讲授过的,所以不再赘述。建议读者在每行的空白处写下对该行代码的注释,说明其作用。这就是所谓的“阅读代码”。“阅读代码”是提升个人编程水平的一种重要方式。
文件保存之后,用下面的方式运行此程序。
如此这般,这个程序就运行起来了。诚然,这里还是非常简单的程序,毕竟只学习了一种类型的对象。要想编写复杂的程序,还要继续学习更多的知识。