翼度科技»论坛 编程开发 python 查看内容

【Python学习笔记】 第5章 数值类型

6

主题

6

帖子

18

积分

新手上路

Rank: 1

积分
18
数值类型基础知识

在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[i:j:k]分片x(...)调用函数/方法/类等等x.attr属性引用(...)元组、表达式、生成器表达式[...]列表、列表推导{...}字典、集合、字典与集合推导混合运算遵循运算符优先级


  • 以上表为标准,运算符从上到下优先级逐渐升高;
  • 如果优先级相同,则从左到右运算。
括号分组子表达式

如果我们使用了括号,就不用考虑优先级,因为Python优先计算括号内的子表达式,再计算整个表达式。
混合类型向上转换

如果表达式中有复数,那么结果就为复数;如果表达式中只有整数和浮点数,则结果为浮点数;如果表达式中只有整数,则结果为整数(除非有除法)。
我们也可以通过强制转换的方法选择想要的类型:
  1. >>> int(3.1415)
  2. 3
  3. >>> float(3)
  4. 3.0
复制代码
预习:运算符重载和多态

我们在之前也看见,+也适用于字符串拼接。这是因为,字符串类型对+进行了重载。用户定义的新类型也可以重载+。
Python的这个特性叫多态。
数字的实际应用

变量与基础表达式

变量是名称,用于记录程序中的信息。在Python中:

  • 变量在第一次赋值时被创建
  • 变量在表达式中被使用时,会被替换为它们的值
  • 变量在表达式中使用之前,必须已经赋值
  • 变量引用对象,不需要事先声明
    例:下面的例子中,自动创建变量a和b:
  1. >>> a = 3
  2. >>> b = 4
复制代码
在表达式中使用刚刚创建的变量,此时变量替换为它们的值:
  1. >>> a + 1, a - 1
  2. (4, 2)
  3. >>> b * 3, b / 2
  4. (12, 2.0)
  5. >>> a % 2, b ** 2
  6. (1, 16)
  7. >>> 2 + 4.0, 2.0 ** b
  8. (6.0, 16.0)
复制代码
注意到,我们输入了多个表达式并用逗号分隔它们,这样Python对每个表达式分别求值,并将它们用元组的方式组合起来。
如果使用还没创建的变量,则Python会报错:
  1. >>> c * 2
  2. Traceback (most recent call last):
  3.   File "<stdin>", line 1, in <module>
  4. NameError: name 'c' is not defined
复制代码
Python解释数值表达式的时候,计算的先后顺序与数学上的优先顺序一致(如先乘除后加减,如果有括号先算括号)
数值的显示格式

在早一些版本,会出现:
  1. >>> b / (2.0 + a)
  2. 0.80000000000000004
  3. >>> print(b / (2.0 + a))
  4. 0.8
复制代码
后面的版本已经解决了这个问题。我们也可以用其他方法显示计算机中数字的位数(比如直接在交互界面输入变量名,或者使用字符串格式化):
  1. >>> num = 1 / 3.0
  2. >>> '%e' % num
  3. '3.333333e-01'
  4. >>> '%4.2f' % num
  5. '0.33'
  6. >>> '{0:4.2f}'.format(num)
  7. '0.33'
复制代码
普通比较与链式比较

普通数值可以进行比较,并返回一个布尔值。
  1. >>> 2.0 >= 1
  2. True
  3. >>> 2.0 != 2.0
  4. False
复制代码
但是,一次比较只能比较两个数,因此Python运行我们把多个比较连接起来:
  1. >>> X = 2
  2. >>> Y = 4
  3. >>> Z = 6
  4. >>> X < Y < Z
  5. True
  6. >>> X < Y and Y < Z
  7. True
复制代码
实际上,前者更有效率,因为Python只计算一次Y。
比较链可以是任意形式,也可以是任意长度。
  1. >>> X < Y > Z
  2. False
  3. >>> 1 < 2 < 3.0 < 4
  4. True
复制代码
如果需要判断表达式是否相等,且用到浮点数,那么对其额外处理(如判断两者的差的绝对值是否小于一个很小的数):
  1. >>> 0.1 + 0.2 == 0.3
  2. False
  3. >>> 0.1 + 0.2
  4. 0.30000000000000004
复制代码
除法、经典除法、向下取整除法和真除法


  • x / y:在Python2.X中,整数取省去小数部分,浮点数保留余项;在Python3.X中,无论用何种类型,都会变成真除法(即保留小数部分)。
  • x // y:向下取整除法。
  1. >>> 10 / 4
  2. 2.5
  3. >>> 10 / 4.0
  4. 2.5
  5. >>> 10 // 4
  6. 2
  7. >>> 10 // 4.0
  8. 2.0
复制代码
可见,//依赖于操作数的类型。
支持两个Python脚本

在Python 2.X中,要实现像Python 3.X的除法效果,需要从模块__future__导入division。
向下取整除法 vs 截断除法

除法//是向下截断除法。对浮点数采用向下截断的函数是math.floor,向零截断的函数是math.trunc,效果如下:
  1. >>> import math
  2. >>> math.floor(2.5)
  3. 2
  4. >>> math.floor(-2.5)
  5. -3
  6. >>> math.trunc(2.5)
  7. 2
  8. >>> math.trunc(-2.5)
  9. -2
复制代码
在Python中,截断除法//总是向下取整。
  1. >>> 5 / 2, 5 / -2
  2. (2.5, -2.5)
  3. >>> 5 // 2, 5 // -2
  4. (2, -3)
  5. >>> 5 / 2.0, 5 / -2.0
  6. (2.5, -2.5)
  7. >>> 5 // 2.0, 5 // -2.0
  8. (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。
复数运算的例子:
  1. >>> 1j * 1J
  2. (-1+0j)
  3. >>> 2 + 1j * 3
  4. (2+3j)
  5. >>> (2 + 1j) * 3
  6. (6+3j)
复制代码
复数允许访问实部和虚部,并支持所有数学表达式和cmath模块中的数学函数。
十六进制、八进制和二进制:字面量与转换

在Python中,编写以0o或0O为开头的字面量,则将其识别为八进制;以0x或0X为开头的字面量,则将其识别为十六进制;以0b或0B为开头的字面量,则将其识别为二进制。
  1. >>> 0o1, 0o20, 0o377
  2. (1, 16, 255)
  3. >>> 0x01, 0X10, 0xFF
  4. (1, 16, 255)
  5. >>> 0b1, 0B10000, 0b11111111
  6. (1, 16, 255)
复制代码
Python默认用十进制显示数值。如果要将一个数转换为八进制、十六进制和二进制,可以分别用oct、hex、bin。
  1. >>> oct(64), hex(64), bin(64)
  2. ('0o100', '0x40', '0b1000000')
复制代码
内置函数int将一个(十进制、八进制、十六进制、二进制)数字字符串转换为一个整数,第一个参数是要转换的字符,第二个参数是要把这个数字字符串看作是几进制,不填则默认为十进制。
  1. >>> int('64'), int('100', 8), int('40', 16), int('1000000', 2)
  2. (64, 64, 64, 64)
  3. >>> int('0x40', 16), int('0b1000000', 2)
  4. (64, 64)
复制代码
eval函数把字符串作为Python代码运行。
字符串格式化方法和表达式把整数转换为指定的字符串:
  1. >>> '{0:o}, {1:x}, {2:b}'.format(64, 64, 64)
  2. '100, 40, 1000000'
  3. >>> '%o, %x, %x, %X' % (64, 64, 255, 255)
  4. '100, 40, ff, FF'
复制代码
注意,在Python3.X中用0开头的数字表示八进制会引发错误。其次,八进制、十六进制和二进制都可以是任意长度的整数。
  1. >>> X = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
  2. >>> X
  3. 25711008708143844408671393477458601640355247900524685364822015
  4. >>> oct(X)
  5. '0o77777777777777777777777777777777777777777777777777777777777777777777'
  6. >>> bin(X)
  7. '0b111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111'
复制代码
按位操作

Python支持C语言中的大多数数学表达式,比如把整数作为二进制串处理的运算(位运算)。如:左移、右移、逻辑与/非/或/异或。
  1. >>> x = 1   # 0001
  2. >>> x << 2  # 0100
  3. 4
  4. >>> x | 2   # 0001 | 0010 = 0011
  5. 3
  6. >>> x & 1   # 0001 & 0001 = 0001
  7. 1
复制代码
在位运算下,之前介绍的二进制、十六进制就十分有用(因为十六进制的每一位对应二进制的四位)。
Python引入了新的整数方法bit_length,查询二进制表示一个数字的值时至少需要的位数。
  1. >>> X = 99
  2. >>> bin(X), X.bit_length(), len(bin(X)) - 2
  3. ('0b1100011', 7, 7)
复制代码
事实上,位运算在Python中不太重要。
其他内置数学工具

内置模块math:
  1. >>> import math
  2. >>> math.pi, math.e                     # 数学常数
  3. (3.141592653589793, 2.718281828459045)
  4. >>> math.sin(2 * math.pi / 180)         # 三角函数
  5. 0.03489949670250097
  6. >>> math.sqrt(144), math.sqrt(2)        # 算术平方根
  7. (12.0, 1.4142135623730951)
  8. >>> pow(2, 4), 2 ** 4, 2.0 ** 4.0       # 幂运算
  9. (16, 16, 16.0)
  10. >>> abs(-42.0), sum((1, 2, 3, 4))       # 绝对值、和
  11. (42.0, 10)
  12. >>> min(3, 1, 2, 4), max(3, 1, 2, 4)    # 序列的最小值、最大值
  13. (1, 4)
复制代码
模块math包含多种取整方式:
  1. >>> math.floor(2.567), math.floor(-2.567)       # 向下取整
  2. (2, -3)
  3. >>> math.trunc(2.567), math.trunc(-2.567)       # 向零取整
  4. (2, -2)
  5. >>> int(2.567), int(-2.567)
  6. (2, -2)
  7. >>> round(2.567), round(2.467), round(2.567, 2) # 四舍五入
  8. (3, 2, 2.57)
复制代码
注意到,优先函数如sin需要导入math,有些则不用。因为这些函数是内置函数,位于隐秘的命名空间内,对应于Python的builtins模块。
随机数random也需要导入。它可以选择在区间\([0, 1]\)的任意实数:
  1. >>> import random
  2. >>> random.random()
  3. 0.83057242993689
  4. >>> random.random()
  5. 0.36589352300294087
  6. >>> random.random()
  7. 0.9102553345613595
复制代码
也可以在规定的范围内选择一个随机整数:
  1. >>> random.randint(1, 10)
  2. 3
  3. >>> random.randint(1, 10)
  4. 9
  5. >>> random.randint(1, 10)
  6. 8
复制代码
还能够从一个序列中随机地选取一项,以及打乱元素:
  1. >>> random.choice(['Life of Brian', 'Holy Grail', 'Meaning of Life'])
  2. 'Holy Grail'
  3. >>> random.choice(['Life of Brian', 'Holy Grail', 'Meaning of Life'])
  4. 'Meaning of Life'
  5. >>>
  6. >>> suits = ['hearts', 'clubs', 'diamonds', 'spades']
  7. >>> random.shuffle(suits)
  8. >>> suits
  9. ['clubs', 'diamonds', 'spades', 'hearts']
  10. >>> random.shuffle(suits)
  11. >>> suits
  12. ['spades', 'clubs', 'hearts', 'diamonds']
复制代码
其他数值类型

小数类型

小数对象的名称是Decimal,它们有固定的位数和小数点,它的精度是固定的。
基础知识

用浮点数来进行运算容易丢失精度:
  1. >>> 0.1 + 0.2
  2. 0.30000000000000004
复制代码
使用了小数对象,则结果更精确:
  1. >>> from decimal import Decimal
  2. >>> Decimal('0.1') + Decimal('0.2')
  3. Decimal('0.3')
复制代码
我们用decimal模块中的Decimal函数创建小数对象,传入一个表示小数的字符串。当不同精度的小数组合,则按照精确度最高的小数给出结果:
  1. >>> Decimal('0.1') + Decimal('0.10')
  2. Decimal('0.20')
复制代码
我们可以从一个浮点数创建小数对象,但它会产生默认庞大的小数位数。
  1. >>> Decimal(0.1) + Decimal(0.2)
  2. Decimal('0.3000000000000000166533453694')
复制代码
设置全局小数精度

默认的小数精度是:小数部分保留28位有效数字。
  1. >>> import decimal
  2. >>> decimal.Decimal(1) / decimal.Decimal(7)
  3. Decimal('0.1428571428571428571428571429')
复制代码
我们可以这么修改显示小数部分有效数字的位数:
  1. >>> decimal.getcontext().prec = 4
  2. >>> decimal.Decimal(1) / decimal.Decimal(7)
  3. Decimal('0.1429')
  4. >>> decimal.Decimal(0.1) + decimal.Decimal(0.2) - decimal.Decimal(0.3)
  5. Decimal('1.110E-17')
复制代码
小数上下文管理器

我们可以把特定的精度要求放在一个环境里,在环境外还是默认精度:
  1. >>> decimal.Decimal('1.00') / decimal.Decimal('3.00')
  2. Decimal('0.3333333333333333333333333333')
  3. >>> with decimal.localcontext() as ctx:
  4. ...     ctx.prec = 2
  5. ...     decimal.Decimal('1.00') / decimal.Decimal('3.00')
  6. ...
  7. Decimal('0.33')
  8. >>> decimal.Decimal('1.00') / decimal.Decimal('3.00')
  9. Decimal('0.3333333333333333333333333333')
复制代码
分数类型

分数基础知识

向上面的Decimal,分数也需要导入模块fraction,并通过两个整数(第一个是分子,第二个是分母)作为参数构造:
  1. >>> from fractions import Fraction
  2. >>> x = Fraction(1, 3)
  3. >>> y = Fraction(4, 6)
  4. >>> x
  5. Fraction(1, 3)
  6. >>> y
  7. Fraction(2, 3)
  8. >>> print(y)
  9. 2/3
复制代码
我们可以把分数用于表达式运算符:
  1. >>> x + y
  2. Fraction(1, 1)
  3. >>> x - y
  4. Fraction(-1, 3)
  5. >>> x * y
  6. Fraction(2, 9)
复制代码
分数和小数的数值精度

分数和小数的运算都比浮点数更直观、准确。而且,分数会自动简化结果。
  1. >>> Fraction(6, 12)
  2. Fraction(1, 2)
复制代码
分数转换和混用类型

浮点数有一个方法,可以将本身转化为分子分母组成的元组。
  1. >>> (2.5).as_integer_ratio()
  2. (5, 2)
复制代码
然后转换为分数,这里*表示将元组的每个元素分别作为函数的参数。
  1. >>> f = 2.5
  2. >>> z = Fraction(*f.as_integer_ratio())
  3. >>> z
  4. Fraction(5, 2)
  5. >>> x = Fraction(1, 3)
  6. >>> float(x)
  7. 0.3333333333333333
  8. >>> float(z)
  9. 2.5
复制代码
注意到,float()可以将分数类型转换为浮点数。Fraction也有一种方法将浮点数转换为分数。
  1. >>> Fraction.from_float(1.75)
  2. Fraction(7, 4)
复制代码
分数加整数的结果是分数,分数加浮点数的结果是浮点数:
  1. >>> x = Fraction(1, 3)
  2. >>> x + 1
  3. Fraction(4, 3)
  4. >>> x + 1.0
  5. 1.3333333333333333
复制代码
但是,如果浮点数不能精确地表达某些实数(如1/3),那么转换为分数结果不精确。
  1. >>> 1.0 / 3
  2. 0.3333333333333333
  3. >>> (1.0 / 3).as_integer_ratio()
  4. (6004799503160661, 18014398509481984)
复制代码
我们可以限制分母地最大值来简化结果:
  1. >>> a = Fraction(*(1.0 / 3).as_integer_ratio())
  2. >>> a
  3. Fraction(6004799503160661, 18014398509481984)
  4. >>> a.limit_denominator(10)
  5. Fraction(1, 3)
复制代码
集合

集合的性质与数学中集合的性质一致。如:无序、没有重复元素。
集合基础知识

我们可以用一个序列或可迭代对象来创建集合:
  1. >>> x = set('abcde')
  2. >>> y = set('bdxyz')
  3. >>> x
  4. {'d', 'a', 'c', 'b', 'e'}
复制代码
集合的运算:
  1. >>> x - y   # 差集
  2. {'a', 'c', 'e'}
  3. >>> x | y   # 并集
  4. {'d', 'x', 'z', 'a', 'c', 'b', 'e', 'y'}
  5. >>> x & y   # 交集
  6. {'d', 'b'}
  7. >>> x ^ y   # 对称差
  8. {'e', 'z', 'a', 'x', 'y', 'c'}
  9. >>> x > y, x < y # 是否为子集
  10. (False, False)
复制代码
集合成员测试in:元素是否在集合/列表/字符串内。
  1. >>> 'e' in x
  2. True
  3. >>> 'e' in 'Camelot', 22 in [11, 22, 33]
  4. (True, True)
复制代码
集合操作还提供了与这些操作对应的方法:
  1. >>> z = x.intersection(y)       # 交集
  2. >>> z
  3. {'d', 'b'}
  4. >>> z.add('SPAM')               # 加入新的元素
  5. >>> z
  6. {'d', 'b', 'SPAM'}
  7. >>> z.update(set(['X', 'Y']))   # 与集合合并(并集)
  8. >>> z
  9. {'Y', 'X', 'b', 'd', 'SPAM'}
  10. >>> z.remove('b')               # 删除一个元素
  11. >>> z
  12. {'Y', 'X', 'd', 'SPAM'}
复制代码
集合可以用于len、for操作,但不适用于索引、分片。
集合操作对应的方法对任何可迭代类型有效:
  1. >>> S = set([1, 2, 3])
  2. >>> S | set([3, 4])
  3. {1, 2, 3, 4}
  4. >>> S | [3, 4]
  5. Traceback (most recent call last):
  6.   File "<stdin>", line 1, in <module>
  7. TypeError: unsupported operand type(s) for |: 'set' and 'list'
  8. >>> S.union([3, 4])
  9. {1, 2, 3, 4}
  10. >>> S.union((3, 4))
  11. {1, 2, 3, 4}
复制代码
新旧版本的集合字面量

对于集合S = {1, 2, 3},新版本(Python2.7,Python3.X)这么显示:
  1. >>> S
  2. {1, 2, 3}
复制代码
旧版本(Python 2.X)这么显示:
  1. >>> S
  2. set([1, 2, 3])
复制代码
空集表示(因此字面量{}的类型是字典):
  1. >>> S - {1, 2, 3}
  2. set()
复制代码
不可变性限制与冻结集合

集合只能包含不变的对象类型。
  1. >>> S = {1.23}
  2. >>> S.add([1, 2, 3])
  3. Traceback (most recent call last):
  4.   File "<stdin>", line 1, in <module>
  5. TypeError: unhashable type: 'list'
  6. >>> S.add({'a': 1})
  7. Traceback (most recent call last):
  8.   File "<stdin>", line 1, in <module>
  9. TypeError: unhashable type: 'dict'
  10. >>> S.add((1, 2, 3))
  11. >>> S
  12. {1.23, (1, 2, 3)}
复制代码
我们可以调用内置的frozenset,这种类型的集合不可改变。
Python 3.X和Python 2.7中的集合推导

集合推导会运行一个循环并在每次迭代时收集一个表达式的结果,通过一个循环变量访问当前的迭代值以用于集合表达式中。
  1. >>> {x ** 2 for x in [1, 2, 3, 4]}
  2. {16, 1, 4, 9}
复制代码
在这个表达式中,循环部分在右侧,集合体表达式在左侧(x ** 2)。意思是:对于列表[1, 2, 3, 4]中的每一个x,给出包含x平方的一个新集合。推导式也适用于迭代其他类型的对象(如字符串)。
为什么使用集合

去除集合体中的重复
  1. >>> L = [1, 1, 4, 5, 1, 4]
  2. >>> set(L)
  3. {1, 4, 5}
  4. >>> list(set(L))
  5. [1, 4, 5]
复制代码
提取可迭代对象的差异,借助集合完成顺序无关的等价性测试。
  1. >>> set(dir(bytes)) - set(dir(bytearray))
  2. {'__bytes__', '__getnewargs__'}
  3. >>> set(dir(bytearray)) - set(dir(bytes))
  4. {'insert', 'reverse', '__delitem__', 'copy', 'extend', '__iadd__', 'pop', 'append', '__imul__', 'clear', 'remove', '__alloc__', '__setitem__'}
  5. >>> L1 = [1, 5, 2, 4, 3]
  6. >>> L2 = [5, 1 ,2, 3, 4]
  7. >>> L1 == L2
  8. False
  9. >>> set(L1) == set(L2)
  10. True
复制代码
布尔型

Python通过判断表达式的真假得到布尔值。
布尔型实际上是特殊的整数类型,True对应1,False对应0。
  1. >>> True + 4
  2. 5
  3. >>> False + 4
  4. 4
复制代码
数值扩展

NumPy可以处理更复杂的数值类型,如向量、矩阵。

来源:https://www.cnblogs.com/hiu-siu-dou/p/18402286
免责声明:由于采集信息均来自互联网,如果侵犯了您的权益,请联系我们【E-Mail:cb@itdo.tech】 我们会及时删除侵权内容,谢谢合作!

举报 回复 使用道具