在 Python 中,数字并不真的是只是一种对象类型,而是一组相似类型的分类。完整的 Python 数值类型工具包括:整数和浮点对象;复数对象;小数:固定精度对象;分数:有理数对象;集合:带有数值运算的集合体;布尔值:真和假;内置函数模块:round、math、random 等;表达式:无限制整数精度;位运算;十六进制、八进制和二进制格式;第三方扩展:向量、库、可视化、作图等。
Python 提供了整数(包括正整数、负整数和零)以及浮点数(带有小数部分的数字)作为其基本类型。
整数写成十进制数字的串。浮点数带一个小数点,也可以加上一个科学技术标志 e 或者 E。浮点数在标准 CPython 中采用 C 语言中的“双精度”来实现,因此,其精度与用来构建 Python 解释器的 C 编译器所给定的精度一样。
Python 2.X 中有两种整数类型:一般整数(通常 32 位)和长整数(无限精度),并且一个整数可以以 l 或 L 结尾,从而强制它转换为长整数。
Python 3.X 中,一般整数和长整数类型合二为一——只有整数这一种,它自动地支持 Python 2.X 中的长整数类型所拥有的无穷精度。因此,整数在程序中不再有末尾的 l 或 L 表示,并且整数也不再显示这个字符。
整数可以编写为十进制(以 10 为基数)、十六进制(以 16 为基数)、八进制(以 8 为基数)和二进制(以 2 为基数)形式。十六进制数以 0x 为 0X 开头,后面接十六进制的数字 0-9 和 A-F。十六进制的数字编写成大写或小写都可以。八进制数字面量以数字 0o 或 0O 开头(数字 0 后面加小写或大写的字母“o”),后面跟数字 0-7 构成的数字串。Python 3.X 中的二进制字面量以 0b 或 0B 开头,后面跟着二进制数字(0-1)。
要注意,所有这些字面量在程序代码中都产生一个整数对象,它们仅仅是特定值的不同语法表示。内置函数 hex(I)、oct(I) 和 bin(I) 把一个整数转换为这 3 种进制表示的字符串,并且 int(str,base) 根据每个给定的进制把一个运行时字符串转换为一个整数。
Python 的复数字面量写成实部 + 虚部的写法,这里虚部是以 j 或 J 结尾。其中,虚部可以独立于实部单独存在。复数也可以通过内置函数 complex(real,imag) 来创建。
表达式的定义是:数字(或其他对象)与运算符相结合,并被 Python 在执行时计算为一个值。
下表为 Python 表达式运算符及程序,在该表中,运算符从上到下优先级逐渐增高,也就是说越下面的表达式“绑定得越紧”。
运算符 | 描述 |
---|---|
yield x | 生成器函数 send 协议 |
lambda args: expression | 创建匿名函数 |
x if y else z | 三元选择表达式(仅当 y 为真时,x 才会被计算) |
x or y | 逻辑或(仅当 x 为假时,y 才会被计算) |
x and y | 逻辑与(仅当 x 为真时,y 才会被计算) |
not x | 逻辑非 |
x in y, x not in y | 成员关系(可迭代对象、集合) |
x is y, x is not y | 对象同一性测试 |
x < y, x <= y, x > y, x >= y | 大小比较,集合的子集和超集 |
x == y, x != y | 值等价性运算符 |
x | y | 按位或、集合并集 |
x ^ y | 按位异或、集合对称差集 |
x & y | 按位与、集合交集 |
x << y, x >> y | 将 x 左移或右移 y 位 |
x + y | 加法、拼接 |
x - y | 减法、集合差集 |
x * y | 乘法、重复 |
x % y | 求余数、格式化 |
x / y, x // y | 真除法、向下取整除法 |
-x, +x | 取负、取正 |
~x | 按位非(取反码) |
x ** y | 幂运算(指数) |
x[i] | 索引(序列、映射等) |
x[i:j:k] | 分片 |
x(...) | 调用(函数、方法、类,其他可调用对象) |
x.attr | 属性引用 |
(...) | 元组、表达式、生成器表达式 |
[...] | 列表、列表推导 |
{...} | 字典、集合、集合与字典推导 |
在混合类型的表达式中,Python 首先将被操作的对象转换成其中最复杂的操作数的类型,然后再对相同类型的操作数进行数学运算。在 Python 中,整数比浮点数简单,浮点数比复数简单。所有这些混合类型转换仅适用于数值类型(例如一个整数和一个浮点数)的混合,这包括那些使用数字和比较运算符的表达式。
在 Python 中:
在 Python 中不需要提前声明变量,但变量在使用之前必须至少被赋值一次。实际上,这意味着在进行累加计数器之前必须先将它们赋值为 0;在列表尾部添加元素之前必须先初始化一个空列表。
str 和 repr 都会把任意对象转换成对应的字符串表示:repr 会产生看起来像代码的结果。str 转换为一种通常对用户更加友好的格式。
>>> repr('spam')
"'spam'"
>>> str('spam')
'spam'
Python 允许将相对大小比较测试链接起来,形成如范围测试的连续比较。例如,表达式(A < B < C)测试了 B 是否位于 A 和 C 直接,等同于布尔测试( A < B and B < C )。
>>> A = 2
>>> B = 4
>>> C = 6
>>> A < B < C
True
>>> A < B and B < C
True
>>> A < B > C
False
>>> A < B and B > C
False
>>> 1 == 2 < 3
False
>>> 1.1 + 2.2 == 3.3
False
>>> 1.1 + 2.2
3.3000000000000003
>>> int(1.1 + 2.2)
3
>>> int(3.3)
3
>>> int(1.1 + 2.2) == int(3.3)
True
除了链接,数值比较是基于相对大小的。可能浮点数不会总是按照预期的想法工作,这是由于浮点数因为有限的比特位数,而不能精确地表示某些值。这是数值编程的一个基本问题,而不只是在 Python 中出现。
除法的行为在 Python 3.X 和 Python 2.X 中略有差异。
X / Y
经典除法和真除法。在 Python 2.X 或之前的版本中,这个操作对于整数会省去小数部分,对于浮点数会保持余项(小数部分)。在 Python 3.X 中将会变成真除法,即无论任何类型,最终的浮点数结果都会保留小数部分。
X // Y
向下取整除法。这是从 Python 2.2 开始新增的操作,在 Python 2.X 和 Python 3.X 中均能使用。这个操作不考虑操作对象的类型,总是会省略结果的小数部分,剩下的最小的能整除的整数部分。它的结果取决于操作数的类型。
概括地说,
在 Python 3.X 中,/ 现在总是执行真除法,不管操作数的类型,都返回包含任何小数部分的一个浮点数结果。// 执行向下取整除法,它截除掉余数并针对整数操作数返回一个整数,如果有任何一个操作数是浮点数类型,则返回一个浮点数。
在 Python 2.X 中,/ 表示经典除法,如果两个操作数都是整数的话,执行截断的整数除法;否则,执行浮点除法。// 执行向下取整除法,并且像在 Python 3.X 中那样工作,对于整数执行截断除法,对于浮点数执行浮点除法。
[root@binguo ~]# python
Python 3.6.1 (default, Sep 19 2019, 17:19:47)
[GCC 4.8.5 20150623 (Red Hat 4.8.5-28)] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> 10 / 4
2.5
>>> 10 / 4.0
2.5
>>> 10 // 4
2
>>> 10 // 4.0
2.0
>>> 10 / 4,10 / -4
(2.5, -2.5)
>>> 10 // 4,10 // -4
(2, -3)
要记得的是,下面的这些字面量只是指定一个整数对象的值的一种替代方式。在 Python 3.X 和 Python 2.X 中编写的如下字面量会产生具有上述 3 种进制数的常规整数。在内存中,同一个整数的值是相同的,它与我们为了指定它而使用的底数无关。
>>> 0o1,0o20,0o377
(1, 16, 255)
>>> 0x01,0x10,0xFF
(1, 16, 255)
>>> 0b1,0b10000,0b11111111
(1, 16, 255)
Python 默认用十进制值(以 10 为底)显示整数数值,也提供了能把整数转换为其他进制的数字字符串(以 Python 字面量的形式)。
>>> oct(64),hex(64),bin(64)
('0o100', '0x40', '0b1000000')
oct 函数将十进制数转为八进制数,hex 函数会将十进制转换为十六进制数,bin 函数会将十进制数转换为二进制。
反过来,内置函数 int 会将一个数字的字符串转换为一个整数,并通过可选的第二位参数来确定转换后数字的进制。
>>> 64,0o100,0x40,0b1000000
(64, 64, 64, 64)
>>> int('64'),int('100',8),int('40',16),int('1000000',2)
(64, 64, 64, 64)
eval 函数,会把字符串作为 Python 代码来运行。因此,它也具有和 int 函数类似的功能,但运行的更慢。实际上 eval 函数会把字符串作为程序的一个片段编译运行,并且假设当前运行的字符串属于一个可信的来源。因此要小心使用 eval 调用。
>>> eval('64'),eval('0o100'),eval('0x40'),eval('0b1000000')
(64, 64, 64, 64)
最后,也可以使用字符串格式化方法调用和表达式(它只返回数字,而不是 Python 的字面量字符串),将整数转换为指定底的字符串:
>>> '{0:o},{1:x},{2:b}'.format(64,64,64)
'100,40,1000000'
>>> '%o,%x,%x,%X' % (64,64,255,255)
'100,40,ff,FF'
下面是实际中 Python 的按位表达式运算符中的一部分,能够实现整数的按位移动及布尔运算:
>>> x = 1
>>> x << 2
4
>>> x | 2
3
>>> x & 1
1
在第一个表达式中,二进制数 1(以 2 为底数,0001)左移了两位,成为二进制的 4(0100)。
第二个表达式实现了一个二进制“或”来组合位(0001|0010=0011)。
第三个表达式实现了一个二进制“和”来选择共同的位(0001&0001=0001)。
在 Python 3.0 中,可以按照位字符串来编写和查看数字。
>>> x = 0b0001
>>> x
1
>>> x << 2
4
>>> bin(x << 2)
'0b100'
>>> bin(x | 0b010)
'0b11'
>>> bin(x & 0b1)
'0b1'
>>> x = 0xFF
>>> x
255
>>> bin(x)
'0b11111111'
>>> bin(x ^ 0b10101010)
'0b1010101'
>>> int('01010101',2)
85
>>> hex(85)
'0x55'
Python 3.1 和 2.7 引入了一个新的整数方法 bit_length,它可以查询以二进制表示一个数字的值时所需的位数。也可以通过内置函数 len,从 bin 字符串的长度减 2(代表字面量字符串开头的“0b”),也可以得到同样的结果。
>>> x = 99
>>> bin(x),x.bit_length(),len(bin(x))-2
('0b1100011', 7, 7)
>>> bin(256),(256).bit_length(),len(bin(256))-2
('0b100000000', 9, 9)
Python 的核心数值类型:整数、浮点数和复数。这里介绍一些 Python 自带的更少见的数值类型。
Python 2.4 中引入一种新的核心数据类型:小数对象。其正式名称是 Decimal。从语法上来讲,需要通过调用已导入模块中的函数来创建小数,而不是通过运行字面量表达式来创建。从功能上讲,小数对象很像浮点数,但它们有固定的位数和小数点。因此,小数是精度固定的浮点数。
使用小数对象,可以得到一个只保留两位小数位精度的浮点数。此外,可以定义如何省略和截断额外的小数数字。
首先,浮点数运算缺乏精确性,这是因为用来存储数值的空间有限。可以使用小数对象是的一些浮点数运算结果更加精确:
>>> 0.1 + 0.1 + 0.1 - 0.3
5.551115123125783e-17
>>> from decimal import Decimal
>>> Decimal('0.1') + Decimal('0.1') + Decimal('0.1') - Decimal('0.3')
Decimal('0.0')
当在表达式中混合使用精度不同的小数时,Python 会自动转换为最高的小数位数。
>>> Decimal('0.1') + Decimal('0.10') + Decimal('0.1') - Decimal('0.3')
Decimal('0.00')
在 Python 2.7、3.1 及之后的版本中,也可以通过 decimal.Decimal.from_float(1.25) 的形式从一个浮点数对象创建小数对象,最新的版本允许直接创建。这一转换是精确的,但有时会产生默认且庞大的小数位数。
>>> Decimal(0.1) + Decimal(0.1) + Decimal(0.1) - Decimal(0.3)
Decimal('2.775557561565156540423631668E-17')
decimal 模块中的其他一些工具可以用来设置所有小数数值的精度,安排错误处理等。
>>> import decimal
>>> decimal.Decimal(1)/decimal.Decimal(7)
Decimal('0.1428571428571428571428571429')
>>> decimal.getcontext().prec = 4
>>> decimal.Decimal(1)/decimal.Decimal(7)
Decimal('0.1429')
>>> decimal.Decimal(0.1) + decimal.Decimal(0.1) + decimal.Decimal(0.1) - decimal.Decimal(0.3)
Decimal('1.110E-17')
在 Python 2.6 和 3.0 及之后的版本中,可以使用 with 上下文管理器语句来临时重置小数精度。
>>> import decimal
>>> decimal.Decimal('1.00')/decimal.Decimal('3.00')
Decimal('0.3333333333333333333333333333')
>>> with decimal.localcontext() as ctx:
... ctx.prec = 2
... decimal.Decimal('1.00')/decimal.Decimal('3.00')
...
Decimal('0.33')
>>> decimal.Decimal('1.00')/decimal.Decimal('3.00')
Decimal('0.3333333333333333333333333333')
Python 2.6 和 3.0 首次引入了新的数值类型 Fraction(分数),它实现了一个有理数对象。本质上,它显式地保持了一个分子和一个分母,从而避免了浮点数运算的某些不精确性和局限性。
分数的使用方式和小数很像。
>>> from fractions import Fraction
>>> x = Fraction(1,3)
>>> y = Fraction(4,6)
>>> x
Fraction(1, 3)
>>> y
Fraction(2, 3)
>>> print(x,y)
1/3 2/3
>>> x + y
Fraction(1, 1)
>>> x - y
Fraction(-1, 3)
>>> x * y
Fraction(2, 9)
>>> Fraction('.25')
Fraction(1, 4)
>>> Fraction('1.25')
Fraction(5, 4)
>>> Fraction(1.25)
Fraction(5, 4)
对浮点数对象进行相同的运算,在内存中它们仍然是不准确的。
>>> a = 1/3.0
>>> b = 4/6.0
>>> a
0.3333333333333333
>>> b
0.6666666666666666
>>> a + b
1.0
>>> a - b
-0.3333333333333333
>>> a * b
0.2222222222222222
在下面的例子中,浮点数并不能准确地给出期望的答案 0,但分数和小数做到了。
>>> 0.1 + 0.1 + 0.1 - 0.3
5.551115123125783e-17
>>> from fractions import Fraction
>>> Fraction(1,10) + Fraction(1,10) + Fraction(1,10) - Fraction(3,10)
Fraction(0, 1)
>>> from decimal import Decimal
>>> Decimal('0.1') + Decimal('0.1') + Decimal('0.1') - Decimal('0.3')
Decimal('0.0')
分数和小数都能提供比浮点数更直观和准确的结果,它们分别通过使用有理数表示以及通过限制精度做到这点。
>>> 1 / 3
0.3333333333333333
>>> Fraction(1,3)
Fraction(1, 3)
>>> import decimal
>>> decimal.getcontext().prec = 2
>>> Decimal(1)/Decimal(3)
Decimal('0.33')
实际上,分数既保持了精确性,又自动简化了结果。
>>> (1 / 3) + (6 / 12)
0.8333333333333333
>>> Fraction(6,12)
Fraction(1, 2)
>>> Fraction(6,12) + Fraction(1,3)
Fraction(5, 6)
>>> decimal.Decimal(str(1/3)) + decimal.Decimal(str(6/12))
Decimal('0.83')
为了支持分数的转换,浮点数对象现在有一个方法,能够产生它们的分子和分母比,分数有一个 from_float 方法,并且 float 函数可以接受一个 Fraction 对象作为参数。
>>> (2.5).as_integer_ratio()
(5, 2)
>>> f = 2.5
>>> z = Fraction(\*f.as_integer_ratio())
>>> z
Fraction(5, 2)
>>> x = Fraction(1,3)
>>> x
Fraction(1, 3)
>>> x +z
Fraction(17, 6)
>>> float(x)
0.3333333333333333
>>> float(z)
2.5
>>> float(x+z)
2.8333333333333335
>>> 17/6
2.8333333333333335
>>> Fraction.from_float(1.75)
Fraction(7, 4)
>>> Fraction(\*(1.75).as_integer_ratio())
Fraction(7, 4)
Python 2.4 引入了集合(set),这是唯一的、不可变的对象的一个无序集合体(collection),这些对象支持与数学集合理论对应的操作。按照定义,一个元素在集合中只能出现一次,不管它被添加了多少次。
因为集合是其他对象的集合体,因此它具有列表和字典这样的对象的某些共同行为。例如,集合是可迭代对象,可以按需增长或缩短,并且可以包含多种对象类型。一个集合的行为很像一个有键无值的字典,不过集合还支持更多的操作。
然而,由于集合是无序的,而且不会把键映射到值,因此它们既不是序列也不是映射类型;它们是自成一体的类型。
要创建一个集合对象,可以向内置的 set 函数传入一个序列或其他可迭代对象:
>>> x = set('abcde')
>>> y = set('bdxyz')
>>> x
{'b', 'd', 'c', 'a', 'e'}
>>> y
{'z', 'd', 'x', 'y', 'b'}
要注意集合并不包含位置顺序——它们的顺序是任意的,且可能随 Python 版本而变化。
集合通过表达式运算符支持一般的数学集合运算。要注意,不能对诸如字符串、列表和元组的一般序列使用下面的运算。
>>> x - y
{'a', 'c', 'e'}
>>> x | y
{'e', 'a', 'y', 'b', 'z', 'c', 'x', 'd'}
>>> x & y
{'b', 'd'}
>>> x ^ y
{'e', 'a', 'y', 'z', 'c', 'x'}
>>> x > y,x < y
(False, False)
该规则很明显的一个例外就是集合成员测试 in。in 表达式也定义为可以在全部其他集合体类型上工作,其作用也是进行成员测试。
>>> 'e' in x
True
>>> 'e' in 'Camelot', 22 in [11,22,33]
(True, True)
集合对象还提供了一些方法来支持集合的修改:add 方法插入一个项目,update 方法在原位置求并集,remove 根据值删除一个元素。并且作为可迭代的容器,集合也可以用于 len,for 循环和列表推导这样的操作。然而,由于集合是无序的,所以不支持像索引和分片这样的操作。
>>> z = x.intersection(y)
>>> z
{'b', 'd'}
>>> z.add('SPAM')
>>> z
{'b', 'SPAM', 'd'}
>>> z.update(set(['x','Y']))
>>> z
{'SPAM', 'b', 'x', 'Y', 'd'}
>>> z.remove('b')
>>> z
{'SPAM', 'x', 'Y', 'd'}
>>> for item in set('abc'): print(item*3)
...
aaa
ccc
bbb
>>> len(z)
4
注意,尽管前面介绍的集合表达式通常需要两个集合,但它们基于方法的对应形式往往可以对任何可迭代类型有效。
>>> S = set([1,2,3])
>>> S | set([3,4])
{1, 2, 3, 4}
>>> S | [3,4]
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unsupported operand type(s) for |: 'set' and 'list'
>>> S.union([3,4])
{1, 2, 3, 4}
>>> S.intersection((1,3,5))
{1, 3}
>>> S.issubset(range(-5,5))
True
集合有一个限制要记住:集合只能包含不可变的(可哈希化的)对象类型。因此,列表和字典不能嵌入集合中,元组是可以嵌入集合的。
>>> S
{1, 2, 3}
>>> S.add([1,2,3,4])
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'list'
>>> S.add({'a':1})
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'dict'
>>> S.add((1,2,3))
>>> S
{1, 2, 3, (1, 2, 3)}
>>> S | {(1,2,3),(4,5,6)}
{1, 2, 3, (1, 2, 3), (4, 5, 6)}
>>> S
{1, 2, 3, (1, 2, 3)}
>>> (1,2,3) in S
True
>>> (1,4,3) in S
False
>>> (1,2) in S
False
集合可以包含模块、类型对象等。集合本身也是可变的,因此,不能直接嵌入其他集合中;如果要在另一个集合中存储一个集合,可以像调用 set 一样调用内置函数 frozenset,但 frozenset 会创建一个不可变的集合,该集合不可修改,并且可以嵌套到其他集合中。
集合推导表达式类似于列表推导的形式。集合推导会运行一个循环并在每次迭代时收集一个表达式的结果,通过一个循环变量来访问当前的迭代值以用于集合表达式中。其结果就是通过运行代码创建了一个新的集合,它具备所有一般的集合行为。
>>> {x ** 2 for x in [1,2,3,4]}
{16, 1, 4, 9}
>>> {x for x in 'spam'}
{'a', 's', 'm', 'p'}
>>> {c * 4 for c in 'spam'}
{'pppp', 'ssss', 'aaaa', 'mmmm'}
>>> S = {c * 4 for c in 'spam'}
>>> S | {'mmmm','xxxx'}
{'xxxx', 'pppp', 'mmmm', 'ssss', 'aaaa'}
>>> S & {'mmmm','xxxx'}
{'mmmm'}
由于项在集合中只能存储一次,因此集合可以用于过滤其他集合体的重复项,注意,元素可能会在该过程中重新排序(因为集合通常是无序的)。
>>> L = [1,2,1,3,2,4,5]
>>> set(L)
{1, 2, 3, 4, 5}
>>> L = list(set(L))
>>> L
[1, 2, 3, 4, 5]
>>> list(set(['yy','cc','aa','xx','dd','aa']))
['yy', 'xx', 'aa', 'dd', 'cc']
集合也可以用于提取列表、字符串以及其他可迭代对象中的差异,只需转换为集合从而获得差异。
>>> set([1,3,5,7]) - set([1,2,4,5,6])
{3, 7}
>>> set('abcdefg') - set('abdghij')
{'e', 'c', 'f'}
>>> set('spam') - set(['h','a','m'])
{'s', 'p'}
>>> set(dir(bytes)) - set(dir(bytearray))
{'__getnewargs__'}
>>> set(dir(bytearray)) - set(dir(bytes))
{'append', '__imul__', 'extend', 'remove', 'copy', 'clear', 'insert', 'pop', '__delitem__', '__iadd__', '__setitem__', '__alloc__', 'reverse'}
也可以通过转换成集合,借助集合进行顺序无关的等价性测试。这是因为顺序在集合中并不重要。两个集合相等当且仅当两个集合中的每一个元素都被另一个集合所包含,也就是说,撇开顺序,每一个集合都是另一个集合的子集。
>>> L1,L2=[1,3,5,2,4],[2,5,3,4,1]
>>> L1 == L2
False
>>> set(L1)==set(L2)
True
>>> sorted(L1)==sorted(L2)
True
可以这样认为,Python 的布尔类型(bool)本质上是数值的,因为它包含两个值 True 和 False,而且就是整数 1 和 0 的定制版,只不过打印时有所不同。更正式的说,Python 有一个名为 bool 的显式布尔数据类型,带有 True 和 False 作为可用且预赋值的内置名称。在内部,名称 True 和 False 是 bool 的实例,而 bool 实际上是内置整数类型 int 的子类(从面向对象的角度来看)。
>>> type(True)
<class 'bool'>
>>> isinstance(True,int)
True
>>> True == 1
True
>>> True is 1
False
>>> True or False
True
>>> True + 4
5
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。