Python数据类型(一)数字类型

Python3有六个标准数据类型:

.不可变数据类型:Number(数字)、String(字符串)、Tuple(元组)

.可变数据类型: List(列表)、Dictionary(字典)、Set(集合)

在每种基本数据类型下会有其它一些衍生类型。以上六种是基本的数据类型,除基本数据类型外,其它数据类型有:Datetime(时间)、Calendar(日历)、Collection(容器)、enum(枚举)等。

该篇讲述Number(数字)的各种类型、衍生类型Decimal类型和Fractions类型的适用情况以及针对数据类型的运算规则。

Number

Python3 支持int、float、bool、complext、Decimal、Fraction 等数值类型,数值类型可以直接进行+、-、*、/运算,()用于分组。内置函数type()isinstance()可以查看变量所指的对象类型,适用于所有的数据类型,两者的区别是type()不认为子类是父类类型 isinstance()认为子类是父类类型。

int(整数)

整数(例如4,5,6)类型为int 类型,Python3之后只有一种整数类型int,表示长整型,不再有之前的long类型。在Python2中用数字0表示False,用数字1表示True,但是Python3 中直接把TrueFalse定义为关键字,其值还是表示0和1。布尔值属于整数的子类型,整数具有无限的精度。

>>> a = 1; b=2
>>> isinstance(a, int)
True
>>> type(b)
<class 'int'> 
#以上两个函数同样适用于其它Number类型以及String等

整数类型附加方法

int 类型实现了numbers.Integral abstract base class,也提供了其他方法

bit_length()

int.bit_length()返回以二进制表示一个整数所需要的位数,不包括符号位和前面的零

>>> a = -13
>>>#转换成二进制
>>> bin(a)
'-0b1101'
>>> a.bit_length()
4

如果a的值为0,则bit_length()函数返回0,如果a的值不为0,则bit_length()是使得2**(k-1) <= abs(x)< 2 **k的 唯一正整数k,同样abs(a)小到足以具有正确的舍入对数时,则k = 1 + int(log(abs(x),2))

等价于:

>>> def bit_length(self):
    s = bin(self)   #将整数转换为二进制
    s = s.lstrip('-0b') #将二进制的前缀去掉
    return len(s)   #返回二进制位的长度

to_bytes()

int.to_bytes(length, byteorder, *,signed=False)返回一个整数的字节数组,是Python3.1新增加的功能

参数含义:

length: 整数字节数,如果不能用给定的字节数来表示则会引发OverflowError

byteorder: 确定用于表示整数的字节顺序,byteorder为’big’表示最高位字节放在字节位开头。byteorder为’little’表示最高位字节放在字节数组的末尾。

signed: 是否使用二进制补码来表示整数,如果signed为False并且给出的是负整数,则会引发OverflowError。默认值为False

>>> a = 1024
>>> a.to_bytes(2, byteorder='big')
b'\x04\x00'
>>> a.to_bytes(10, byteorder='big')
b'\x00\x00\x00\x00\x00\x00\x00\x00\x04\x00'
>>> a.to_bytes(10, byteorder='big', signed=True)
b'\x00\x00\x00\x00\x00\x00\x00\x00\x04\x00'
>>> b = -1024
>>> b.to_bytes(10, byteorder='big', signed=True)
b'\xff\xff\xff\xff\xff\xff\xff\xff\xfc\x00'
>>> c = 1000
>>> c.to_bytes((c.bit_length()+7)//8, byteorder='little')
b'\xe8\x03'

from_bytes()

int.from_bytes(bytes, byteorder, *, signed=False) 返回给定字节数组表示的整数,是Python3.2增加的功能。

参数含义:

bytes: 必须是一个bytes-like object 或是生成字节的可迭代对象

byteorder: 表示整数的字节顺序,如果 byteorder 为 "big",则最高位字节放在字节数组的开头。 如果 byteorder 为 "little",则最高位字节放在字节数组的末尾

signed:是否使用二进制补码表示

>>> int.from_bytes(b'\x04\x00',byteorder='big')
1024
>>> int.from_bytes(b'\x00\x00\x00\x00\x00\x00\x00\x00\x04\x00', byteorder='big')
1024
>>> int.from_bytes(b'\xff\xff\xff\xff\xff\xff\xff\xff\xfc\x00', byteorder='big',signed=True)
-1024

float(浮点数)

带小数部分的数字(如:4.5,6.78)是float类型float()函数可以将数字转换为float类型。浮点数通常使用C中的double来实现,浮点数精度和内部表示可以查看sys.float_info

>>> float(8)
8.0

浮点数类型附加方法

float 类型实现了 numbers.Real abstract base class。 float 具有以下附加方法。

as_integer_ratio()

float.as_integer_ratio() 返回一对整数,其比率证照等于原浮点数并且分母为整数,如果是无穷大会引发 OverflowError 而 NaN 则会引发 ValueError

>>> 2.5.as_integer_ratio()
(5, 2)

is_integer()

float.is_integer() 如果float实例可以用有限位整数表示则返回True,否则返回False

>>> 2.0.is_integer()
True
>>> 3.3.is_integer()
False

注意点

以上两个方法都支持与十六进制数、字符串之间转换。由于 Python 浮点数在内部存储为二进制数,因此浮点数与 十进制数 字符串之间的转换往往会导致微小的舍入错误。 而十六进制数字符串却允许精确地表示和描述浮点数。 这在进行调试和数值工作时非常有用。

hex()

float.hex() 以十六进制字符串的形式返回一个浮点数,如果是有限浮点数,这种表示法将包含前导的 0x 和尾随的 p 加指数,此方法是实例方法

>>> 4.7.hex()
'0x1.2cccccccccccdp+2'
>>> 3.3.hex()
'0x1.a666666666666p+1'

fromhex()

float.fromhex()类方法,返回以十六进制字符串 s 表示的浮点数的类方法,返回的字符串可以带有前导和尾随的空格

>>> float.fromhex('0x1.a666666666666p+1')
3.3
>>> float.fromhex('0x1.2cccccccccccdp+2')
4.7

complex(复数)

complext由实部re和虚部im构成,实部和虚部都是浮点类型,使用后缀j和J表示虚数部分,表示为a+bj,函数complex(re,im)同样可以构造复数。

>>> complex(4.5, 1.2)
(4.5+1.2j)

复数极坐标

Python中复数本质上实现是一个长方形坐标系或由笛卡尔坐标系存储。它被定义为实部和虚部:

z=z.real + z.imag*1j

极坐标系 提供了可供选择的表达复数的方式,在极坐标系中复数z被定义为是由模数r和位项角phi构成。模数r是由z到原点的距离,位项角phi是正x轴到原点与z轴连接线段按弧度计算的逆时针角度。

The modulus r is the distance from z to the origin, while the phase phi is the counterclockwise angle, measured in radians, from the positive x-axis to the line segment that joins the origin to z

有关于复数极坐标的转换函数可以查看:Python运算(三)cmath模块

Decimal(十进制定点和浮点数)

Decimal能够快速正确舍入十进制,为十进制浮点运算提供支持。Decimal是基于浮点模型,方便十进制浮点数科学运算,并且提高来精确性。Decimal保留尾数零,如1.30 + 1.70 = 3.001.20 *1.40 =1.6800 ;

具有严格相等不变量的会计或金融程序中,会优先选择Decimal类型,举例来说,1.0-1.0 结果恰好为0,但是在二进制数值中结果为5.5511151231257827e-017,虽然无限接近于0,但是仍然存在误差,若用Decimal则不会存在这样的误差,其结果为0;Decimal作为十进制的浮点数可以设置精度(默认为28个精度)

Decimal由十进制数信号、和算数上下文组成。

Decimal构成——十进制数

值的注意的是Decimal中的十进制数与整型的十进制数并不完全相同,Decimal中的十进制数由符号、系数数字和指数构成,系数数字不截断尾数零,并且十进制数包括特殊字符(如:Infinity-Infinity以及NaN),并且还区分-0 和 + 0即代表同样都是0但是-0+0 在Decimal中是两个不同的数字。

如:利用整数、字符串、浮点或元组(这些类型后面会讲到)构造十进制实例,NaN 在这里并不代表空值,而是代表”非数字”

>>> getcontext().prec = 6
>>> Decimal(10)
Decimal('10')
>>> Decimal('3.1415')
Decimal('3.1415')
>>> Decimal(3.14)
Decimal('3.140000000000000124344978758017532527446746826171875')
>>> Decimal((0,(3,1,4),-2))
Decimal('3.14')
>>> Decimal(str(2.0**0.5))
Decimal('1.4142135623730951')
>>> Decimal(2) ** Decimal('0.5')
Decimal('1.41421')
>>> Decimal('NaN')
Decimal('NaN')
>>> Decimal('-Infinity')
Decimal('-Infinity')

若Decimal(value)中并没有给value赋值,则会返回Decimal('0')

如果value是tuple,则有三个组件,一个符号、一个数字的tuple、和整数指数,如上面的代码Decimal((0,(3,1,4),-2)) ,返回Decimal('3.14')

如果value是float,则二进制浮点值无损地转换为其精确的十进制等效值。该转换通常需要50位精度或更高位数的精度转换,例如上面代码中Decimal(3.14)转换为Decimal('3.140000000000000124344978758017532527446746826171875')

Decimal构成——信号

信号是计算过程中出现的异常条件。根据程序需要,信号有时会被忽略,有时被视为信息,也有可能被视为异常。每个信号,由一个标志和一个陷阱启动器构成,遇到信号时,其标志设置为 1 ,若陷阱启用器设置为 1 ,则引发异常,并且用户需要在监控计算之前重置标志。信号有Clamped 、 InvalidOperation 、 DivisionByZero 、 Inexact 、 Rounded 、 Subnormal 、 Overflow 、 Underflow 以及 FloatOperation

若FloatOperation信号被捕获,若使用浮点数进行构造Decimal或者浮点数做排序和比较运算,则会抛出异常,但等于比较不会引发异常。

>>> context = getcontext()
>>> context.traps[FloatOperation] = True
>>> Decimal(3.14)
Traceback (most recent call last):
  File "<pyshell#23>", line 1, in <module>
    Decimal(3.14)
decimal.FloatOperation: [<class 'decimal.FloatOperation'>]
>>> Decimal('3.4') < 3.5
Traceback (most recent call last):
  File "<pyshell#24>", line 1, in <module>
    Decimal('3.4') < 3.5
decimal.FloatOperation: [<class 'decimal.FloatOperation'>]
>>> Decimal('3.5')==3.5
True

Decimal构成——算术上下文

算术上下文是指精度、舍入规则、指数限制、指示操作结果的标志以及信号被视为异常的陷阱启动器的环境。

舍入选项包括 ROUND_CEILING 、 ROUND_DOWN 、 ROUND_FLOOR 、 ROUND_HALF_DOWNROUND_HALF_EVEN 、 ROUND_HALF_UP 、 ROUND_UP 以及 ROUND_05UP。 用函数getcontext()可以访问当前上下文,并可以更改设置。Context()函数可以创建算数上下文,若启用备用上下文,则需要setcontext()函数。

>>> from decimal import *
>>> getcontext()
Context(prec=28, rounding=ROUND_HALF_EVEN, Emin=-999999, Emax=999999, capitals=1, clamp=0, flags=[], traps=[InvalidOperation, DivisionByZero, Overflow])
>>> getcontext().prec = 6

Decimal提供了两个现成的上下文BasicContext 和 ExtendedContextBasicContext启用了许多陷阱对调试起到很大作用。算数上下文的另一个作用就是监视计算期间遇到的异常情况信号标志,举例见上文中信号部分示例。

Decimal 常数

常数是C语言模块,但是完全可以和Python和谐共存。其中Decimal的常数有:

常数名称 32-bit 64-bit
decimal.MAX_PREC 425000000 999999999999999999
decimal.MAX_EMAX 425000000 999999999999999999
decimal.MIN_EMIN -425000000 -999999999999999999
decimal.MIN_ETINY -849999999 -1999999999999999997

另外,还有一个比较特别的常数 decimal.HAVE_THREADS, 默认值为True,但如果Python被编译的时候没有开辟线程,C会自动的杀死本地运行环境中开销比较大的线程,这种情况下,值为False

Decimal方法

除了标准的数字属性,Decimal也有许多专门方法,并且方法很多

方法名 含义 代码示例
adjuested() 移除系数最右边数字之后返回调整后的指数,直到只剩下前导数字  
as_integer_ratio() 返回一对(n,d)整数,表示给Decimal实例作为分数最简形式并带正分母 >>> Decimal(‘-3.14’).as_integer_ratio()
(-157, 50)
as_tuple() 返回一个tuple表示的数值 DecimalTuple(sign, digits, exponent)
canonical() 返回参数的规范编码  
compare() 比较两个Decimal实例的值 a or b is a NaN ==> Decimal(‘NaN’) a < b ==> Decimal(‘-1’) a == b ==> Decimal(‘0’) a > b ==> Decimal(‘1’)
compare_signal() 除了所有的NaN信号之外,此操作与compare()方法相同  
compare_total() 使用抽象表示来比较 两个操作数  
compare_total_mag 使用抽象表示来比较,但忽略操作数的符号  
conjugate() 返回自身,只符合Decimal规范  
copy_abs() 返回参数的绝对值,操作不受上下文影响,不执行舍入  
copy_negate() 返回参数的否定值,符号设置与第二个操作数符号相同 >>> Decimal(‘2.3’).copy_sign(Decimal(‘-1.5’)) Decimal(‘-2.3’)
exp(context=None) 返回给定数字的指数函数,结果使用ROUND_HALF_EVEN模式舍入 >>> Decimal(1).exp() Decimal(‘2.718281828459045235360287471’) >>> Decimal(321).exp() Decimal(‘2.561702493119680037517373933E+139’)
from_float() 将浮点数转换为十进制数,Python3.2之后可以直接用float构造  
fma(other,third,context=None) 混合乘法加法,返回self *other+third,乘积不会四舍五入 >>> Decimal(2).fma(3, 5) Decimal(‘11’)
is_canonical() 参数是规范的,则为返回 [True],否则为 [False]  
is_finite() 参数是有限数 则返回True,否则返回Fasle  
is_infinite() 参数为正负无穷大,则返回True,否则为False  
is_nan() 如果参数为Nan,则返回True,否则返回False  
is_normal(context=None) 如果参数是一个有限正规数,返回 True,如果参数是0、次正规数、无穷大或是NaN,返回 False  
is_qnan() 同is_nan()  
is_signed() 如果参数带有负数,返回True,否则返回False  
is_snan() 如果参数为显示NaN,则返回True,否则返回False  
is_subnormal(context=None) 如果参数为低于给定值,则返回 True,否则返回 False。  
is_zero() 如果参数是0(正负皆可),则返回True,否则返回False

Decimal参数很多,这里不一一列举了,更多函数可以参考Deccimal标准库

Decimal 注意点

新版本Python3.3之后,congtext精度不会影响存储的位数,完全由value中的位数决定,context精度和舍入仅在算数期间发挥作用。context参数的目的是确定value是格式错误的字符串时该怎么做,如果context陷阱InvalidOperation则引发 异常,否则构造函数返回一个新的Decimal,其值为NaN。构造完成后Decimal对象是不可变的。Python3.6之后允许下划线进行分组。

>>> from decimal import *
>>> getcontext().prec = 6
>>> Decimal('3.1415926535')
Decimal('3.1415926535')
>>> Decimal('3.1415926535') + Decimal('2.7182818285')
Decimal('5.85987')
>>> getcontext().rounding = ROUND_UP
>>> Decimal('3.1415926535') + Decimal('2.7182818285')
Decimal('5.85988')

Fraction(分数):

Fraction分数类型可以由一系列整型数值,或其它数字类型,又或者是string(字符串)构造。

Fraction构建方式

Fraction构建形式为:

Fraction(numerator=0, denominator=1)
Fraction(other_fraction)
Fraction(float)
Fraction(decimal)
Fraction(string)

第一种构建方式,需要一个符合数字类型的数值当分子,和一个符合数字类型的数值当分母,构造函数会返回一个分子/分母值的Fraction实例。众所周知,分数分母不能为0,如果分母为0,会出现ZeroDivisionError的错误。

第二种构建方式也必须要求是一个符合数字类型的数值当分子,返回同样值的一个fraction分数实例。

第三种和第四种构建方式接受数字类型为float类型和Decimal类型,返回一个精确的具有同样数值大小的Fraction分数实例。不过由于二进制浮点数问题,类似于Fraction(1.1)并不能准确地返回类似于Fration(11,10)这样的分数实例。具体的构建规则,由函数limit_denominator()决定(该函数后面会涉及)。

最后一种构建方式用string字符串类型或unicode类型构建,一般形式为:

[符号] 分子'/'分母 如:Fraction('-3/7')

>>> from fractions import Fraction
>>>#第一种构建方式
>>> Fraction(-4, 5)
Fraction(-4, 5)
>>> Fraction(3, 8)
Fraction(3, 8)
>>>#第二种构建方式
>>> Fraction()
Fraction(0, 1)
>>>#第三种构建方式
>>> Fraction(2.30)
Fraction(2589569785738035, 1125899906842624)
>>> Fraction(Decimal ('1.1'))
Fraction(11, 10)
>>>#第四种构建方式
>>> Fraction('-3/7')
Fraction(-3, 7)
>>> Fraction('7e-6')
Fraction(7, 1000000)

Fraction类型继承字基本数据类型(numbers.Rational),并继承了基类中的方法和操作。Fraction类型能够进行哈希运算,并且是不可变类型。

Fraction属性和方法

属性:

numerator: 分子

denominator: 分母

方法:

方法名 含义 代码
from_float(flt) 类方法,用float构建Fraction实例 Python3.2之后的方法  
from_decimal(dec) 类方法,用Decimal构建Fraction实例,同样是Python3.2之后才有  
limit_denominator (max_denominator=100000) 查找并返回一个和构造Fraction类数值接近,且分母是不超过设置的max_denominator的最大分母;该方法用来寻找与给定浮点数相近比例数,以及纠正一个近似float类型的比例数值 >>> from fractions import Fraction
>>> Fraction(‘3.1415926’).limit_denominator(1000)
Fraction(355, 113)
>>> from math import pi, cos
>>> Fraction(cos(pi/3))
Fraction(4503599627370497, 9007199254740992)
>>> Fraction(cos(pi/3)).limit_denominator()
Fraction(1, 2)
>>> Fraction(1.1).limit_denominator()
Fraction(11, 10)
>>>
floor() 返回一个<= 分数自身的 int类型值,也可用数学模块中的math.floor() >>> from math import floor
>>> floor(Fraction(335,113))
2
ceil() 返回一个>=分数自身的最小int值,同样可以用数学模块中的math.ceil()  
round() /round(ndigits) round()返回Fraction的四舍五入最接近的int值; round(ndigits)返回Fraction(1, 10*ndigits)最接近的倍数数 >>> round(Fraction(4.8))
5
>>> round(Fraction(4.5))
4
>>> round(Fraction(4.3))
4
>>> round(Fraction(4.389089), 3)
Fraction(4389, 1000)
fractions.gcd(a,b) 返回整数a和b最大公约数, Python3.5之后用math.gcd()代替 >>> import fractions
>>> fractions.gcd(2,3)
1
>>> fractions.gcd(36, 24)
12

round()函数注意点

round()默认会进行四舍五入,但我们发现在上面的代码中

>>> round(Fraction(4.5))
4

4.5四舍五入值应该为5,但是给出的结果是4。

这是因为Python3.5 之后round()函数如果遇到浮点距离两边一样远,会保留到偶数那一边,doc中的原话为:”values are rounded to the closest multiple of 10 to the power minus ndigits; if two multiples are equally close, rounding is done toward the even choice.” 

因为4.5 距离4 和距离5 都是0.5的距离,但因为4是偶数,所以最后结果是偶数4。如果是5.5的话,结果就是6

>>> round(5.5)
6

不过在Pyton2 中就不会有这个问题,round()函数会保留到离上一位更近的一端,即远离0的一端。

瞬间是不是觉得有点坑,如果代码从Python2 迁移到Python3 涉及到了大量round()函数的话,就比较坑,所以建议如果是要进行数据运算,还是尽量使用math或cmath模块中的函数。

此外,除来以上问题之外,还存在着一个问题:浮点数精度问题

例如代码

>>> round (2.565, 2)
2.56

无论是Python2 还算Python3 以上代码得到的结果都是2.56,显然这不符合常理。这是因为数字的存储都是用二进制,如果换算成二进制后一串1和0后可能是无限位数的,机器已经做出了截断处理,那么2565这个数字就比实际数字要小一点点。这一点点就导致了它离2.56要更近一点点,所以保留两位小数时就近似到了2.56。

那round()函数对精度把控不准,有替代函数吗?

1.像上面提到的,使用math中函数替代 ,如math.ceiling

2.Python自带整除//

3.可以将浮点型做截断转成字符串

有关具体的各类Number运算,详见:Python运算(-)数值、哈希、布尔等运算

猜你喜欢

转载自blog.csdn.net/u010670117/article/details/115059084