Python基础数据类型
(1)整型int
基本数据类型的值都可通过字面值(literal)的形式表示出来,即以字面形式表现值。 整数类型的字面值表示形式和我们在现实世界中的写法一样,例如下列都是合法的整数:
123 -456 0
注意,整数字面值是不能包含小数点的,即使小数点后面什么都没有!读者也许会觉得 这句话很奇怪,因为在数学中从没见过一个数包含小数点但小数点后面啥也没有的情形。然 而,在 Python 中确实允许以下形式的字面值:
123. -456. 0.
但它们都不是整数!事实上,以上三个数分别等于 123.0、-456.0 和 0.0,它们属于后 文即将介绍的浮点数类型。
Python 语言为整数类型提供了通常的数学运算,运算符及其含义如下表所示:
运算符 | 含义 |
---|---|
+ | 加 |
- | 减 |
* | 乘 |
/ | 除 |
** | 乘方 |
% | 取余数 |
abs() | 取绝对值 |
例如:
>>> 23 + 45
68
>>> 56 – 12
44
>>> 8 * 2
16
>>> 11 / 3
3
>>> 8 ** 2
64
>>> 18 % 5
3
>>> abs(-8)
8
可见,计算机实现的整数运算基本上和我们在数学课上所学的一样,除了一个例外—— 除法。由于例中的 11/3 是整数类型上的除法,运算结果仍然在整数类型当中,所以 Python 将商的小数部分直接舍弃了(未作四舍五入!),从而结果为 3。在程序中,本来希望得到精 确的除法结果,但因被除数和除数都是整数,导致结果误差过大甚至出错,这是初学 Python 编程的人很容易防错误的地方。要说明一下,表 2.1 中的 abs()并不是运算符,而是 Python 的内建函数,这里只是为了方便而将它列在了表中。
除了上面这些运算符,Python 还提供了一些运算符与变量赋值结合起来的表示法。例 如,在程序设计中经常用到一个变量递增的操作:x = x + 1。注意,这个式子在数学中 是不成立的,因为一个数不可能“等于”该数加 1。但在编程语言中这是一个完全合法的赋 值语句,它的含义是:将变量 x 所指向的值加 1,并将计算结果重新赋值给 x。鉴于这个操 作频繁使用,Python 和某些其他语言提供了一种简写形式:x += 1。请看例子:
>>> x = 123
>>> x += 1
>>> print x
124
还有其他一些类似的简写形式,参见下表
普通形式 | 简写形式 |
---|---|
x = x + y | x += y |
x = x - y | x -= y |
x = x * y | x *= y |
x = x / y | x /= y |
x = x % y | x %= y |
赋值与运算结合
int 类型的局限性
计算思维是建立在计算机的能力和限制之上的。现在我们来讨论整数类型的一个限制。
int 类型只是数学中的整数集合 I 在计算机中的表示,而一个事物和该事物的一种表示 之间未必可以划等号。事实上,类型 int 只表示了 I 的一个子集,I 是无穷集合,而 int 是有穷的。这是为什么呢?
在计算机底层,整数一般都是用特定长度的二进制数表示的。至于具体长度是多少,取 决于 CPU 的设计。目前个人计算机上多采用 32 个二进制位(bit,比特)的长度来表示整数, 故 Python 语言中的 int 类型就是 32 比特长度的整数值。利用一点排列组合知识,容易推 知:一个比特有两种可能的状态(0、1),两个比特有四种可能的状态(00、01、10、11), 三个比特有八种状态(000、001、010、011、100、101、110、111),…,32 个比特有 232种可能的状态。用这 232 种状态显然只能表示 232 个整数,考虑到整数有正负,计算机底层 将这 232 个状态的一半用于表示非负整数,另一半用于表示负整数,从而类型 int 实际上是 由-231~231-1 之间的所有整数构成的集合①。
我们已经了解,数据是现实世界信息在计算机中的抽象,根据数据值的种类和操作的不 同而划分成不同数据类型。一般来说在逻辑层次上理解和使用数据类型就够了,不需要进一 步了解这些抽象在计算机底层的物理表示。然而,如果能对数据类型的底层表示方法有所了解,可以使数据和程序设计更好地建立在机器的能力和限制之上。
① 有的语言还支持用 32 比特表示 0~232-1 的无符号整数。
(2)浮点型float
浮点数就是包含小数点的数,大体对应于数学中的实数集合。现实世界中的职工工资(以 元为单位)、房屋面积(以平方米为单位)、人的身高(以米为单位)、圆周率等在程序中都 适合用浮点数表示。
Python 语言提供了类型 float 用于表示浮点数。float 类型的字面值形式与数学中的 写法基本一致,但是允许小数点后面没有任何数字(表示小数部分为 0),例如下列字面值 都是浮点数:
3.1415 -6.78 123.0 0\. -6.
Python 为浮点数类型提供了通常的加减乘除等运算,运算符与整数类型是一样的。但是,与整数类型不同的是,运算符“/”用于浮点数时,是要保留小数部分的, 例如:
>>> 11.0 / 3.0
3.6666666666666665
没错,最后一位小数是 5 而不是 6!原因见下面关于浮点数内部表示的内容。 将一个浮点数赋值给变量,则该变量就是 float 类型(实际上是指向一个 float 类型的数据)。例如:
>>> f = 3.14
>>> type(f)
<type 'float'>
浮点数运算同样可以和变量赋值结合起来
浮点数的能力与限制 浮点数类型能够表示巨大的数值,能够进行高精度的计算。但是,由于浮点数在计算机
内是用固定长度的二进制表示的,有些数可能无法精确地表示,只能存储带有微小误差的近 似值。例如,
>>> 1.2 – 1.0
0.19999999999999996
结果比 0.2 略小。又如:
>>> 2.2 – 1.2
1.0000000000000002
结果比 1.0 略大。然而,下面这个表达式却计算出了精确结果:
>>> 2.0 – 1.0
1.0
尽管浮点表示带来的这种微小误差不至于影响数值计算实际应用,但在程序设计中仍然 可能导致错误。例如,万一某个程序中需要比较 2.2 ? 1 是否等于 1.2,那我们就得不到 预期的肯定回答,因为 Python 的计算结果是不相等!请看下面两个比较式:
>>> (1.2 – 1.0) == 0.2
False
>>> (2.0 – 1.0) == 1.0
True
先解释一下,上例中用到了比较两个表达式是否相等的运算符“==”,另外显示结果出 现了表示真假的布尔值 True 和 False,这些内容在后面布尔类型一节中有详细介绍。从 这个例子我们得到一条重要的经验:不要对浮点数使用==来判断是否相等。正确的做法是 检查两个浮点数的差是否足够小,是则认为相等。例如:
>>> epsilon = 0.0000000000001
>>> abs((1.2 – 1.0) - 0.2) < epsilon
True
另外从运算效率考虑,与整数类型 int 相比,浮点数类型 float 的运算效率较低,由 此我们得出另一条经验:如果不是必须用到小数,那就应当使用整数类型。
科学记数法
对于很大或很小的浮点数,Python 会自动以科学记数法来表示。所谓科学记数法就是
以“a×10 的整数次幂”的形式来表示数值,其中 1 <= abs(a) < 10。例如,12345 可 以表示成 1.2345e+4,0.00123 可以表示为 1.2345e-3。下面是 Python 的计算例子:
>>> 1234.5678 ** 9
6.662458388479362e+27
>>> 1234.5678 ** -9
1.5009474606688535e-28
正如 int 不同于整数集 I 一样,Python 的 float 也不同于实数集 R,因为 float 仍 然只能表示有限的浮点数。当一个表达式的结果超出了浮点数表示范围的时候,Python 会 显示结果为 inf(无穷大)或-inf(负无穷)。读者可以做一个有趣但略显麻烦的实验,试 一试 Python 最大能表示多大的浮点数。下面是本书著者所做的实验结果,可以看到,最大 浮点数的数量级是 10308,有效数字部分已经精确到小数点后面第 53 位(Python 在显示结果 时只保留小数点后 16 位),当该位为 6 时是合法的浮点数,当该位为 7 时则超出范围。
>>> 1.79769313486231580793728971405303415079934132710037826e+308
1.7976931348623157e+308
>>> 1.79769313486231580793728971405303415079934132710037827e+308
inf
顺便说一下,如果读者做这个实验,相信你一定会采用一种快速有效的策略来确定每一 位有效数字,而不会对每一位都从 0 试到 9。例如,当发现 1.7…1e+308 是合法的浮点数, 而 1.7…9e+308 超出了范围,接下去应当检查 1.7…5e+308 的合法性。这种方法就是本 书后面算法设计一章中介绍的二分查找策略。我们在第 1 章说过,计算思维人人皆有、处处 可见,不是吗?
自动类型转换
float 类型与 float 类型的数据相互运算,结果当然是 float 类型。问题是 float 类型能与 int 或 long 类型进行运算吗?
由于整数、长整数和浮点数都是数值(在数学上都属于实数集合 R),因此 Python 允许它们混合运算,就像 int 可以与 long 混合运算一样。Python 在对混合类型的表达式进行 求值时,首先将 int 或 long 类型转换成 float,然后再执行 float 运算,结果为 float 类型。例如:
>>> type(2 + 3.0)
<type 'float'>
>>> type(2 + 3L * 4.5)
<type 'float'>
手动类型转换
除了在计算混合类型的表达式时 Python 自动进行类型转换之外,有时我们还需要自己 手动转换类型。这是通过几个类型函数 int()、long()和 float()实现的。例如,当我 们要计算一批整型数据的平均值,程序中一般会先求出这批数据的总和 sum,然后再除以数 据的个数 n,即:
average = sum / n
但这个结果未必如我们所愿,因为 sum 和 n 都是整数,Python 执行的是整数除法,小数部 分被舍弃了,导致结果误差太大。为解决此问题,我们需要手动转换数据类型:
average = float(sum) / n
其中 float()函数将 int 类型的 sum 转换成了 float 类型,而 n 无需转换,因为 Python 在计算 float 与 int 混合的表达式时,会自动将 n 转换成 float 类型。
要注意的是,下面这种转换方式是错误的:
average = float(sum/n)
因为括号里的算式先计算,得到的就是整除结果,然后再试图转换成 float 类型时,已经 为时已晚,小数部分已经丢失了。
其实,调用类型函数来手动转换类型并不是好方法,我们有更简单、更高效的做法。如 果已知的数据都是整数类型的,而我们又希望得到浮点类型的结果,那么我们可以将表达式 涉及的某个整数或某一些整数加上小数点,小数点后面再加个 0,这样整数运算就会变成浮 点运算。例如求两个整数的平均值:
>>> x = 3
>>> y = 4
>>> z = (x + y) / 2.0
>>> z
3.5
例中我们人为地将数据个数 2 写成了 2.0,这样就使计算结果变成了 float 类型。 当然,在将浮点数转换成整数类型时,就没有这种简便方法了,只能通过类型函数来转换。例如:
>>> int(3.8)
3
>>> long(3.8)
3L
可见,float 类型转换成 int 或 long 时,只是简单地舍去小数部分,并没有做四舍五入。 如果希望得到四舍五入的结果,一个小技巧是先为该值(正数)加上 0.5 再转换。更一般 的方法是调用内建函数 round(),它专门用于将浮点数转换成最接近的整数部分。不过舍 入后的结果仍然是 float,为了得到 int 类型的数据还需要再用 int()转换。例如:
>>> round(3.14)
3.0
>>> round(-3.14)
-3.0
>>> round(3.5)
4.0
>>> round(-3.5)
-4.0
>>> int(round(-3.14))
-3
bool
判断两个数是否相等时,Python给我们返回了布尔类型的结果,那么什么是布尔类型呢?
布尔是19世纪英国的数学家,他建立了命题代数,所谓的命题就是可以判断命题真假的语句。在编程语言中,将真假两个值组成了一个类型,即布尔类型,真假值也称为布尔值,以真假为值的表达式称为布尔表达式,布尔表达式在程序中的作用是根据条件的真假执行对应的语句。
Python在2.3版本之后就定义了布尔类型bool,bool类型的两个值为True和False。在2.3版本之前,Python用1和0来表示真、假,这个方法沿用至今。
>>> if 1:
... print('true')
... else:
... print('false')
...
true
布尔表达式最常用的是判断两个表达式的数值大小关系的。
[表达式] [运算符] [表达式]
>>> 2 == 2
True
但布尔表达式在判断字符串的时候就不那么简单了。
>>> 'cyberkid' == 'cyberkid'
True
>>> 'cyberkid' == 'CYBERKID'
False
在Python中,字符串是按字典的顺序进行比较的,也就是说是基于字母顺序比较,而字母顺序是按照ASCII编码顺序排列的。所以,不管是大小写字母,标点符号,阿拉伯数字以及各种字符也是要按照ASCII编码来确定大小。
>>> 3 > 3
False
>>> 3 > 2
True
>>> 2 * 2 > 2
True
>>> 'like' > 'lake'
True
那么,我们怎么查看这些数字、字母、标点符号在ASCII编码中的位置大小呢?我们可以通过ord函数来查看。
>>> ord('1')
49
>>> ord('a')
97
>>> ord('A')
65
>>> ord(',')
44
>>> ord('<')
60
ord函数返回字符在ASCII中的位置序号。
当然,仅用简单的布尔表达式不足以满足某些需求,将多个简单的布尔表达式用逻辑运算符连接起来组成复杂的布尔表达式,回顾一下我们学过的逻辑运算符:and、or、not。
[布尔表达式] and [布尔表达式]
[布尔表达式] or [布尔表达式]
not [布尔表达式]
在上图中,P和Q是参加运算的布尔表达式,T和F表示真假值。在and中,P和Q各有两种可能的值,所以P、Q组合共有4中不同的值组合,每种组合在表中一行表示,后面一列是P and Q的值,从表中可知,只有当P、Q都为真,并且P and Q为真,整个表达式为真。
>>> 3 > 3 and 3 < 4
False
>>> 3 > 2 and 3 < 4
True
在or中,只有P or Q为假,且P、Q也为假,表达式为假,也就是说,只要其中一项为真,则表达式为真。
>>> 3 > 3 or 3 < 4
True
>>> 3 > 3 or 3 == 4 or 3 == 3
True
not的用法相对简单。
>>> not 3 > 3
True
>>> not not 3 > 3
False
上例中,not not 3 > 3
语句相当于我们生活中的双重否定为肯定。利用这三个逻辑运算符可以构建复杂的布尔型表达式。在复杂的布尔表达式中,同算数运算符一样,谁先谁后计算成了问题,这就要牵扯到运算符的优先级了,回顾一下上一小节中我们列出运算符的优先级的图,可以看到逻辑运算符的优先级。
not > and > or
在此再介绍一种别的语言不支持的表达式形式。
>>> 3 > 2 < 4
True
>>> 3 > 2 < 4 == 4 != 5
True
虽然这在数学中常用,但我们仍不推荐这种方式,因为这不为大多数语言所接受,对于这类表达式,还是用逻辑运算符比较好。
小结:有时候适当的加括号,来改变原有的优先级,就像数学运算中加括号改变计算顺序一样如计算:2 * (2 + 2)。
>>> print( 0 or not 0 or '')
True
>>> print( 0 or not 0 or '' and 1)
True
>>> print( 0 or not 0 or '' and 1 and 0)
True
>>> print( 0 or not 0 or '' and 1 and 0 and None)
True
>>> print( (0 or not 0 or '') and 1 and 0 and None)
0
>>> print( (0 or not 0 or '') and 1 and 0 or None)
None
>>> print( (0 or not 0 or '') and 1 and 0 or None)
None
通过上面的例子,我们可以发现,返回值是有一定的规律的。
如果用x、y表示任何表达式。
x and y
and中,如果x的值为false,则返回x的值,否则返回y的值。
>>> 1 and 0
0
>>> 0 and 1
0
or中,如果x的值为false,则返回y的值,否则返回x的值。
>>> 0 or 1
1
>>> 1 or 0
1
not中,如果x的值为false,则返True,否则返回False。
>>> x = 0
>>> not x
True
>>> y = 1
>>> not y
False
>>> not not y
True
注意:Python中,元素自带布尔值,也就是说,每个元素都有自己的布尔值,我们可以通过bool函数来证明。
>>> bool(0)
False
>>> bool(1)
True
>>> bool(None)
False
>>> bool('')
False
>>> bool([])
False
>>> bool(-1)
True
由上例可以看到,在Python中,0、None、空为假,其余为真。 注意:空包括,空的字符串,空的容器类型。
(4)复数类型complex
Python用complex表示复数类型,但由于不常用,我们只做了解。
在数学中,任意数可表示为a + bi,a称为实部,b称为虚部;而Python中complex类型的表示方法为(a + bj)。
注意,Python中的complex类型的虚数符号用j表示,而不是数学中的i,在不会产生误解的情况下,(a + bj)可以省略括号为a + bj。
complex类型也可以执行数学运算。
>>> c1 = 3 + 5j
>>> c2 = 2 + 4j
>>> c1 + c2
(5+9j)
>>> c1 - c2
(1+1j)
>>> c1 * c2
(-14+22j)
>>> c1 ** c2
(-0.5249747542492873+0.16891854983884866j)
>>> abs(c1)
5.830951894845301
需要注意的是,abs函数对复数的计算是返回复数的模数。 我们也可以通过c1.real()和c1.imag()来分别获取c1的实数和虚数,结果都是float类型。
>>> c1 = 3 + 5j
>>> c2 = 2 + 4j
>>> c1.real
3.0
>>> c1.imag
5.0
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本