【Python学习笔记】 第5章 数值类型
数值类型基础知识在Python中,数值实际上是一种类型的分类,包括:
[*]整数、浮点数
[*]复数
[*]小数:固定精度对象
[*]分数:有理数对象
[*]集合:带有数值运算的集合体
[*]布尔值:True, False
[*]内置函数与块:round,math,random等
[*]表达式、无限制精度整数(很大的整数)、位运算、八进制、十二进制、二进制
[*]第三方扩展:向量、库、可视化、作图等
其中整数、浮点数最为常见,因此先从它们讲起。
数值字面量
字面量解释1234, -24, 0, 99999999999999整数(无大小限制)1.23, 1., 3.14e-10, 4E210, 4.0e+210浮点数0o177, 0x9ff, 0b101010Python 3.X中八进制、十六进制、二进制字面量0177, 0o177, 0x9ff, 0b101010Python 2.X中两种八进制、十六进制、二进制字面量3+4j, 3.0+4.0j, 3J复数字面量set('spam'), {1, 2, 3, 4}集合Decimal('1.0'), Fraction(1, 3)小数、分数扩展bool(X), True, False布尔类型、字面量注意:
[*]浮点数带小数点,或加上科学技术标志e/E。如果字面量带有上述描述,那么将其识别为浮点数。
[*]整数:在Python2中有32位整数和长整数(无限制长),Python3中只有整数,即无限长的整数。
[*]十六进制、八进制和二进制字面量:八进制以0o或0O开头,十六进制以0x开头,二进制以0b或0B开头。
[*]复数:字面量位实部+虚部,虚部以j或J结尾。
内置数值工具
处理数字的工具包括:
[*]表达式运算符
[*]内置数学函数
[*]工具模块
它们也有一些专用于特定类型的方法。
Python表达式运算符
表达式的定义:数字/变量与运算符相结合,在执行时计算为一个值。
Python所有的运算符表达式如下:
运算符描述yield x生成器函数send协议lambda args: expression创造匿名函数(lambda表达式)x if y else z三元选择表达式,如果y为真则取x,否则取zx or y逻辑或x and y逻辑与not x逻辑非x in y, x not in yx是/不是y的成员x is y, x is not y`对象是否同一(不止是值相等)x < y, x > y, x = yx是否小于/大于/不大于/不小于yx == y, x != yx等于/不等于y(和上面的is不一样)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 ** yx的y次幂x索引x分片x(...)调用函数/方法/类等等x.attr属性引用(...)元组、表达式、生成器表达式[...]列表、列表推导{...}字典、集合、字典与集合推导混合运算遵循运算符优先级
[*]以上表为标准,运算符从上到下优先级逐渐升高;
[*]如果优先级相同,则从左到右运算。
括号分组子表达式
如果我们使用了括号,就不用考虑优先级,因为Python优先计算括号内的子表达式,再计算整个表达式。
混合类型向上转换
如果表达式中有复数,那么结果就为复数;如果表达式中只有整数和浮点数,则结果为浮点数;如果表达式中只有整数,则结果为整数(除非有除法)。
我们也可以通过强制转换的方法选择想要的类型:
>>> int(3.1415)
3
>>> float(3)
3.0预习:运算符重载和多态
我们在之前也看见,+也适用于字符串拼接。这是因为,字符串类型对+进行了重载。用户定义的新类型也可以重载+。
Python的这个特性叫多态。
数字的实际应用
变量与基础表达式
变量是名称,用于记录程序中的信息。在Python中:
[*]变量在第一次赋值时被创建
[*]变量在表达式中被使用时,会被替换为它们的值
[*]变量在表达式中使用之前,必须已经赋值
[*]变量引用对象,不需要事先声明
例:下面的例子中,自动创建变量a和b:
>>> a = 3
>>> b = 4在表达式中使用刚刚创建的变量,此时变量替换为它们的值:
>>> a + 1, a - 1
(4, 2)
>>> b * 3, b / 2
(12, 2.0)
>>> a % 2, b ** 2
(1, 16)
>>> 2 + 4.0, 2.0 ** b
(6.0, 16.0)注意到,我们输入了多个表达式并用逗号分隔它们,这样Python对每个表达式分别求值,并将它们用元组的方式组合起来。
如果使用还没创建的变量,则Python会报错:
>>> c * 2
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'c' is not definedPython解释数值表达式的时候,计算的先后顺序与数学上的优先顺序一致(如先乘除后加减,如果有括号先算括号)
数值的显示格式
在早一些版本,会出现:
>>> b / (2.0 + a)
0.80000000000000004
>>> print(b / (2.0 + a))
0.8后面的版本已经解决了这个问题。我们也可以用其他方法显示计算机中数字的位数(比如直接在交互界面输入变量名,或者使用字符串格式化):
>>> num = 1 / 3.0
>>> '%e' % num
'3.333333e-01'
>>> '%4.2f' % num
'0.33'
>>> '{0:4.2f}'.format(num)
'0.33'普通比较与链式比较
普通数值可以进行比较,并返回一个布尔值。
>>> 2.0 >= 1
True
>>> 2.0 != 2.0
False但是,一次比较只能比较两个数,因此Python运行我们把多个比较连接起来:
>>> X = 2
>>> Y = 4
>>> Z = 6
>>> X < Y < Z
True
>>> X < Y and Y < Z
True实际上,前者更有效率,因为Python只计算一次Y。
比较链可以是任意形式,也可以是任意长度。
>>> X < Y > Z
False
>>> 1 < 2 < 3.0 < 4
True如果需要判断表达式是否相等,且用到浮点数,那么对其额外处理(如判断两者的差的绝对值是否小于一个很小的数):
>>> 0.1 + 0.2 == 0.3
False
>>> 0.1 + 0.2
0.30000000000000004除法、经典除法、向下取整除法和真除法
[*]x / y:在Python2.X中,整数取省去小数部分,浮点数保留余项;在Python3.X中,无论用何种类型,都会变成真除法(即保留小数部分)。
[*]x // y:向下取整除法。
>>> 10 / 4
2.5
>>> 10 / 4.0
2.5
>>> 10 // 4
2
>>> 10 // 4.0
2.0可见,//依赖于操作数的类型。
支持两个Python脚本
在Python 2.X中,要实现像Python 3.X的除法效果,需要从模块__future__导入division。
向下取整除法 vs 截断除法
除法//是向下截断除法。对浮点数采用向下截断的函数是math.floor,向零截断的函数是math.trunc,效果如下:
>>> import math
>>> math.floor(2.5)
2
>>> math.floor(-2.5)
-3
>>> math.trunc(2.5)
2
>>> math.trunc(-2.5)
-2在Python中,截断除法//总是向下取整。
>>> 5 / 2, 5 / -2
(2.5, -2.5)
>>> 5 // 2, 5 // -2
(2, -3)
>>> 5 / 2.0, 5 / -2.0
(2.5, -2.5)
>>> 5 // 2.0, 5 // -2.0
(2.0, -3.0)为什么截断很重要
Python 3.X中的非截断行为会严重影响大量的Python 2.X程序。
整数精度
Python 3.X支持无限制的整数大小,但Python 2.X识别长整数时在末尾加一个L。这方便了高精度运算(在C/C++需要额外实现)。
复数
复数的后缀为j或J,我们可以把实部非0的复数写成实部与虚部相加的形式。比如,实部为2,虚部为-3的复数可以写为2 + -3j或2 - 3j。
复数运算的例子:
>>> 1j * 1J
(-1+0j)
>>> 2 + 1j * 3
(2+3j)
>>> (2 + 1j) * 3
(6+3j)复数允许访问实部和虚部,并支持所有数学表达式和cmath模块中的数学函数。
十六进制、八进制和二进制:字面量与转换
在Python中,编写以0o或0O为开头的字面量,则将其识别为八进制;以0x或0X为开头的字面量,则将其识别为十六进制;以0b或0B为开头的字面量,则将其识别为二进制。
>>> 0o1, 0o20, 0o377
(1, 16, 255)
>>> 0x01, 0X10, 0xFF
(1, 16, 255)
>>> 0b1, 0B10000, 0b11111111
(1, 16, 255)Python默认用十进制显示数值。如果要将一个数转换为八进制、十六进制和二进制,可以分别用oct、hex、bin。
>>> oct(64), hex(64), bin(64)
('0o100', '0x40', '0b1000000')内置函数int将一个(十进制、八进制、十六进制、二进制)数字字符串转换为一个整数,第一个参数是要转换的字符,第二个参数是要把这个数字字符串看作是几进制,不填则默认为十进制。
>>> int('64'), int('100', 8), int('40', 16), int('1000000', 2)
(64, 64, 64, 64)
>>> int('0x40', 16), int('0b1000000', 2)
(64, 64)eval函数把字符串作为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'注意,在Python3.X中用0开头的数字表示八进制会引发错误。其次,八进制、十六进制和二进制都可以是任意长度的整数。
>>> X = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
>>> X
25711008708143844408671393477458601640355247900524685364822015
>>> oct(X)
'0o77777777777777777777777777777777777777777777777777777777777777777777'
>>> bin(X)
'0b111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111'按位操作
Python支持C语言中的大多数数学表达式,比如把整数作为二进制串处理的运算(位运算)。如:左移、右移、逻辑与/非/或/异或。
>>> x = 1 # 0001
>>> x << 2# 0100
4
>>> x | 2 # 0001 | 0010 = 0011
3
>>> x & 1 # 0001 & 0001 = 0001
1在位运算下,之前介绍的二进制、十六进制就十分有用(因为十六进制的每一位对应二进制的四位)。
Python引入了新的整数方法bit_length,查询二进制表示一个数字的值时至少需要的位数。
>>> X = 99
>>> bin(X), X.bit_length(), len(bin(X)) - 2
('0b1100011', 7, 7)事实上,位运算在Python中不太重要。
其他内置数学工具
内置模块math:
>>> import math
>>> math.pi, math.e # 数学常数
(3.141592653589793, 2.718281828459045)
>>> math.sin(2 * math.pi / 180) # 三角函数
0.03489949670250097
>>> math.sqrt(144), math.sqrt(2) # 算术平方根
(12.0, 1.4142135623730951)
>>> pow(2, 4), 2 ** 4, 2.0 ** 4.0 # 幂运算
(16, 16, 16.0)
>>> abs(-42.0), sum((1, 2, 3, 4)) # 绝对值、和
(42.0, 10)
>>> min(3, 1, 2, 4), max(3, 1, 2, 4) # 序列的最小值、最大值
(1, 4)模块math包含多种取整方式:
>>> math.floor(2.567), math.floor(-2.567) # 向下取整
(2, -3)
>>> math.trunc(2.567), math.trunc(-2.567) # 向零取整
(2, -2)
>>> int(2.567), int(-2.567)
(2, -2)
>>> round(2.567), round(2.467), round(2.567, 2) # 四舍五入
(3, 2, 2.57)注意到,优先函数如sin需要导入math,有些则不用。因为这些函数是内置函数,位于隐秘的命名空间内,对应于Python的builtins模块。
随机数random也需要导入。它可以选择在区间\(\)的任意实数:
>>> import random
>>> random.random()
0.83057242993689
>>> random.random()
0.36589352300294087
>>> random.random()
0.9102553345613595也可以在规定的范围内选择一个随机整数:
>>> random.randint(1, 10)
3
>>> random.randint(1, 10)
9
>>> random.randint(1, 10)
8还能够从一个序列中随机地选取一项,以及打乱元素:
>>> random.choice(['Life of Brian', 'Holy Grail', 'Meaning of Life'])
'Holy Grail'
>>> random.choice(['Life of Brian', 'Holy Grail', 'Meaning of Life'])
'Meaning of Life'
>>>
>>> suits = ['hearts', 'clubs', 'diamonds', 'spades']
>>> random.shuffle(suits)
>>> suits
['clubs', 'diamonds', 'spades', 'hearts']
>>> random.shuffle(suits)
>>> suits
['spades', 'clubs', 'hearts', 'diamonds']其他数值类型
小数类型
小数对象的名称是Decimal,它们有固定的位数和小数点,它的精度是固定的。
基础知识
用浮点数来进行运算容易丢失精度:
>>> 0.1 + 0.2
0.30000000000000004使用了小数对象,则结果更精确:
>>> from decimal import Decimal
>>> Decimal('0.1') + Decimal('0.2')
Decimal('0.3')我们用decimal模块中的Decimal函数创建小数对象,传入一个表示小数的字符串。当不同精度的小数组合,则按照精确度最高的小数给出结果:
>>> Decimal('0.1') + Decimal('0.10')
Decimal('0.20')我们可以从一个浮点数创建小数对象,但它会产生默认庞大的小数位数。
>>> Decimal(0.1) + Decimal(0.2)
Decimal('0.3000000000000000166533453694')设置全局小数精度
默认的小数精度是:小数部分保留28位有效数字。
>>> 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.2) - decimal.Decimal(0.3)
Decimal('1.110E-17')小数上下文管理器
我们可以把特定的精度要求放在一个环境里,在环境外还是默认精度:
>>> 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')分数类型
分数基础知识
向上面的Decimal,分数也需要导入模块fraction,并通过两个整数(第一个是分子,第二个是分母)作为参数构造:
>>> from fractions import Fraction
>>> x = Fraction(1, 3)
>>> y = Fraction(4, 6)
>>> x
Fraction(1, 3)
>>> y
Fraction(2, 3)
>>> print(y)
2/3我们可以把分数用于表达式运算符:
>>> x + y
Fraction(1, 1)
>>> x - y
Fraction(-1, 3)
>>> x * y
Fraction(2, 9)分数和小数的数值精度
分数和小数的运算都比浮点数更直观、准确。而且,分数会自动简化结果。
>>> Fraction(6, 12)
Fraction(1, 2)分数转换和混用类型
浮点数有一个方法,可以将本身转化为分子分母组成的元组。
>>> (2.5).as_integer_ratio()
(5, 2)然后转换为分数,这里*表示将元组的每个元素分别作为函数的参数。
>>> f = 2.5
>>> z = Fraction(*f.as_integer_ratio())
>>> z
Fraction(5, 2)
>>> x = Fraction(1, 3)
>>> float(x)
0.3333333333333333
>>> float(z)
2.5注意到,float()可以将分数类型转换为浮点数。Fraction也有一种方法将浮点数转换为分数。
>>> Fraction.from_float(1.75)
Fraction(7, 4)分数加整数的结果是分数,分数加浮点数的结果是浮点数:
>>> x = Fraction(1, 3)
>>> x + 1
Fraction(4, 3)
>>> x + 1.0
1.3333333333333333但是,如果浮点数不能精确地表达某些实数(如1/3),那么转换为分数结果不精确。
>>> 1.0 / 3
0.3333333333333333
>>> (1.0 / 3).as_integer_ratio()
(6004799503160661, 18014398509481984)我们可以限制分母地最大值来简化结果:
>>> a = Fraction(*(1.0 / 3).as_integer_ratio())
>>> a
Fraction(6004799503160661, 18014398509481984)
>>> a.limit_denominator(10)
Fraction(1, 3)集合
集合的性质与数学中集合的性质一致。如:无序、没有重复元素。
集合基础知识
我们可以用一个序列或可迭代对象来创建集合:
>>> x = set('abcde')
>>> y = set('bdxyz')
>>> x
{'d', 'a', 'c', 'b', 'e'}集合的运算:
>>> x - y # 差集
{'a', 'c', 'e'}
>>> x | y # 并集
{'d', 'x', 'z', 'a', 'c', 'b', 'e', 'y'}
>>> x & y # 交集
{'d', 'b'}
>>> x ^ y # 对称差
{'e', 'z', 'a', 'x', 'y', 'c'}
>>> x > y, x < y # 是否为子集
(False, False)集合成员测试in:元素是否在集合/列表/字符串内。
>>> 'e' in x
True
>>> 'e' in 'Camelot', 22 in
(True, True)集合操作还提供了与这些操作对应的方法:
>>> z = x.intersection(y) # 交集
>>> z
{'d', 'b'}
>>> z.add('SPAM') # 加入新的元素
>>> z
{'d', 'b', 'SPAM'}
>>> z.update(set(['X', 'Y'])) # 与集合合并(并集)
>>> z
{'Y', 'X', 'b', 'd', 'SPAM'}
>>> z.remove('b') # 删除一个元素
>>> z
{'Y', 'X', 'd', 'SPAM'}集合可以用于len、for操作,但不适用于索引、分片。
集合操作对应的方法对任何可迭代类型有效:
>>> S = set()
>>> S | set()
{1, 2, 3, 4}
>>> S |
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unsupported operand type(s) for |: 'set' and 'list'
>>> S.union()
{1, 2, 3, 4}
>>> S.union((3, 4))
{1, 2, 3, 4}新旧版本的集合字面量
对于集合S = {1, 2, 3},新版本(Python2.7,Python3.X)这么显示:
>>> S
{1, 2, 3}旧版本(Python 2.X)这么显示:
>>> S
set()空集表示(因此字面量{}的类型是字典):
>>> S - {1, 2, 3}
set()不可变性限制与冻结集合
集合只能包含不变的对象类型。
>>> S = {1.23}
>>> S.add()
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.23, (1, 2, 3)}我们可以调用内置的frozenset,这种类型的集合不可改变。
Python 3.X和Python 2.7中的集合推导
集合推导会运行一个循环并在每次迭代时收集一个表达式的结果,通过一个循环变量访问当前的迭代值以用于集合表达式中。
>>> {x ** 2 for x in }
{16, 1, 4, 9}在这个表达式中,循环部分在右侧,集合体表达式在左侧(x ** 2)。意思是:对于列表中的每一个x,给出包含x平方的一个新集合。推导式也适用于迭代其他类型的对象(如字符串)。
为什么使用集合
去除集合体中的重复
>>> L =
>>> set(L)
{1, 4, 5}
>>> list(set(L))
提取可迭代对象的差异,借助集合完成顺序无关的等价性测试。
>>> set(dir(bytes)) - set(dir(bytearray))
{'__bytes__', '__getnewargs__'}
>>> set(dir(bytearray)) - set(dir(bytes))
{'insert', 'reverse', '__delitem__', 'copy', 'extend', '__iadd__', 'pop', 'append', '__imul__', 'clear', 'remove', '__alloc__', '__setitem__'}
>>> L1 =
>>> L2 =
>>> L1 == L2
False
>>> set(L1) == set(L2)
True布尔型
Python通过判断表达式的真假得到布尔值。
布尔型实际上是特殊的整数类型,True对应1,False对应0。
>>> True + 4
5
>>> False + 4
4数值扩展
NumPy可以处理更复杂的数值类型,如向量、矩阵。
来源:https://www.cnblogs.com/hiu-siu-dou/p/18402286
免责声明:由于采集信息均来自互联网,如果侵犯了您的权益,请联系我们【E-Mail:cb@itdo.tech】 我们会及时删除侵权内容,谢谢合作!
页:
[1]