Learning Python Part I之数字类型(Numeric Types)

在Python中,数据都采用对象的形式–包括Python内置的对象和我们通过Python工具或其他语言例如C等创造的对象,对象是Python中最基本的概念。

数字类型基础

在Python中,数字并不是单一的对象类型,而是包含一类相似的类型,Python支持通常的数字类型如整数和浮点型,而且支持更高级的数字类型和对象,Python中的数字工具包括:

  1. 整型和浮点型对象(integer and float-point objects)
  2. 复数对象(Complex number objects)
  3. 十进制运算(Decimal)
  4. 分数(Fraction)
  5. 集合(Sets)
  6. 布尔型(Booleans)
  7. 内置函数和模块(Build-in function and modules)
  8. 表达式,无限制的整数精度,位操作,十六进制,十进制和二进制的格式化
  9. 第三方扩展(Third-party extensions)

数字表达形式:

在Python中数字不需要提前声明,但在使用前必须提前赋值,否则会报错(或者说必须有初始值),并且在Python2.x中,整数包含两种类型:短型(normal)和长型(long),当数字过大时Python会在内部自动将数字转为长型,以L结尾标注;但在Python3.x中,整数只是一种单一的类型,不在区分,方便的同时当数字逐渐增大后运行也会相应变慢。

这里写图片描述

表达式运算符

表达式是最基本的处理数字的工具,下表列出了Python中可用的算符:

这里写图片描述

值得注意的是 ( A < B < C ) 和 ( A < B and B < C ) 等价的;还有数字比较符是基于大小的,当遇到浮点型的时候可能并不会像想象的那样工作

>>> 1.1 + 2.2 == 3.3
False
>>> 1.1 + 2.2 
3.3000000000000003
>>> int(1.1 + 2.2) == int(3.3)
True

除法:

在Python中除法,并且在2.x 和 3.x中有些区别:

X / Y :

真除;在Python2.x中会将小数部分舍去只有当除数和被除数中有小数时结果保留小数部分;在Python3.x中,无论除数和被除数类型,始终保留小数部分。

X // Y :

整除;从Python2.2之后加入的除法符号,这种除法会一直舍去小数部分,结果的类型取决于除数和被除数的类型
C:\code> C:\Python33\python
>>> 10 / 4 # Differs in 3.X: keeps remainder
2.5
>>> 10 / 4.0 # Same in 3.X: keeps remainder
2.5
>>> 10 // 4 # Same in 3.X: truncates remainder
2
>>> 10 // 4.0 # Same in 3.X: truncates to floor
2.0
C:\code> C:\Python27\python
>>> 10 / 4  # This might break on porting to 3.X!
2
>>> 10 / 4.0
2.5
>>> 10 // 4  # Use this in 2.X if truncation needed
2
>>> 10 // 4.0
2.0

如何兼容两个版本

为了解决 ” / ” 在不同的版本中不同的问题,可以有两种方法使其兼容不同版本。

X = Y / Z #只是用整除,在2.x或3.x中都返回相同结果
X = Y / float(Z) #使用float()保证结果是小数

或者也可以通过import语句在2.x中打开3.x的 ” / ” 功能

>>> 10 / 4
2
>>> from __future__ import division
>>> 10 / 4
2.5
>>> 10 // 4
2

两种舍位取整的区别(Floor versus truncation)

floor division 取的是比其小的最大整数,而truncating division 是直接舍去小数位,在运算整数时两种没有区别,但在运算负数时结果会不相同:

>>> import math
>>> math.floor(2.5)
2
>>> math.floor(-2.5)
-3
>>> math.trunc(2.5)
2
>>> math.trunc(-2.5)
-2

当运行除法运算符时,运行的是floor除法:
在3.x中

>>> 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)

在2.x中

>>> 5 / 2, 5 / -2
(2, -3)
>>> 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)

复数

复数类型并不常见,他们在工程和科学计算中用的比较多。
复数可以用标准库cmath(math模块中的复数部分),因为并不常见,所以不在这里详细介绍,用到的时候可以去查看python在线手册

十六进制、八进制和二进制

>>> oct(64),hex(64),bin(64)
('0o100', '0x40', '0b1000000')
>>> int('64'),int('100',8),int('40', 16), int('100000', 2)
(64, 64, 64, 32)
>>> int('0x40',16),int('0b1000000',2)
(64, 64)

位操作

除了一些常用的加减操作之外,Python支持大部分C语言中的操作,这也包括处理二进制位,这些操作在Python处理例如网络数据包、串口或者C语言产生的二进制数据包时很有用。

>>> x = 1
>>> x << 2 #将x左移两位
4
>>> x | 2 #x 与 2  相或
3
>>> x & 1 #x 与 1 相与
>>> 1

bit_length():

这个方法可以查询用二进制表示一个值需要多少位,不过用len()也能实现同样的效果。

>>> 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)

其他内置工具:

math模块:

以下举例一部分,具体的可查看python在线手册

>>> 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.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) # Round (Python 3.X version)
>>> '%.1f' % 2.567, '{0:.2f}'.format(2.567)
('2.6', '2.57')
>>> (1 / 3.0), round(1 / 3.0, 2), ('%.2f' % (1 / 3.0))
(0.3333333333333333, 0.33, '0.33')

三种实现求平方根的方法:

>>> import math
>>> math.sqrt(144)
12.0
>>> 144 ** .5
12.0
>>> pow(144, .5)
12.0
>>> math.sqrt(1234567890)
35136.41828644462
>>> 1234567890 ** .5
35136.41828644462
>>> pow(1234567890, .5)
35136.41828644462

random模块:

这个模块提供了像求随机值,随机挑选数字这一类的工具

>>> import random
>>> random.random()
0.25880066905091026
>>> random.random()
0.986742321398632
>>> random.randint(1,10)
10
>>> random.randint(1,10)
7
>>> import random
>>> suits = ['hearts', 'clubs', 'diamonds', 'spades']        
>>> random.shuffle(suits)
>>> suits
['hearts', 'diamonds', 'clubs', 'spades']
>>> random.shuffle(suits)
>>> suits
['diamonds', 'hearts', 'spades', 'clubs']

其他数字类型

Decimal类型

因为存储数值的空间有限,所以浮点型运算有时候很不精确,例如:

>>> print(0.1 + 0.1 + 0.1 - 0.3)
5.551115123125783e-17
>>> 0.1 + 0.1 + 0.1 - 0.3                                       
5.551115123125783e-17 #这个值很小,以至于与0特别接近

通过decimal,我们可以更精确的运算

>>> from decimal import Decimal
>>> Decimal('0.1') + Decimal('0.1') + Decimal('0.1') - Decimal('0.3')
Decimal('0.0')

设置精准度:

Decimal模块中的其他工具可以做很多事情,例如设置精准度等。

>>> import decimal
>>> decimal.Decimal(1) / decimal.Decimal(7)
Decimal('0.1428571428571428571428571429')
# Default: 28 digits
>>> decimal.getcontext().prec = 4
>>> decimal.Decimal(1) / decimal.Decimal(7)
Decimal('0.1429') # Fixed precision
>>> Decimal(0.1) + Decimal(0.1) + Decimal(0.1) - Decimal(0.3)
Decimal('1.110E-17')

分数类型(Fraction)

Fraction函数实现一个有理数对象,同时保存分子和分母,如此避免浮点型运算的不精准和限制。尽管它不会像浮点型运算一样在有限的硬件环境下取一个最接近的值,但是当以后用到时,它会提供更真实的数据。

>>> from fractions import Fraction #和random类似,需要引入模块
>>> x = Fraction(1, 3)
>>> y = Fraction(4, 6)
>>> x , y
(Fraction(1, 3), Fraction(2, 3))
>>> print(x)
1/3

Fraction也可以进行算术运算:

>>> 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('.25') + Fraction('1.25')
Fraction(3, 2)

Fraction和Decimal的区别

两种都是浮点类型运算的不同形式,浮点型运算被浮点运算硬件所限制。这种限制在所需要表示的数需要的二进制位超出了存储空间的大小的时候更加明显。Fraction和Decimal都是提供了一种方法获得精确的结果,尽管以冗长的代码和缓慢的速度(相对而言)为代价。例如在计算0.1 + 0.1 + 0.1 - 0.3的运算中,浮点运算只会取一个无限接近与零的值,而Fraction和Decimal可以得到结果0

>>> 0.1 + 0.1 + 0.1 - 0.3
5.551115123125783e-17
# This should be zero (close, but not exact)
>>> 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')

Fraction 的类型转化和混合运算

浮点型转化为分数:

>>> (2.5).as_integer_ratio() #float对象的方法,生成相应的分子和分母
(5, 2)
>>> f = 2.5
>>> z = Fraction(*f.as_integer_ratio())
>>> z
Fraction(5, 2)

分数转换为浮点数:

>>> 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)
>>> Fraction('1.75')
Fraction(7, 4)

混合运算:

>>> x
Fraction(1, 3)
>>> x + 2
Fraction(7, 3)
>>> x + 2.0
2.3333333333333335
>>> x + (1./3)
0.6666666666666666
>>> x + (4./3)
1.6666666666666665
>>> x + Fraction(4, 3)
Fraction(5, 3)

值得注意的是当把浮点型数转换为分数时,一些情况下会产生不可避免的精准度缺失应为原始数据——浮点型 本身就是不精确的,必要的时候我们可以通过设置分母最大值的方法简化结果:

>>> from fractions import Fraction
>>> 4.0 /3
1.3333333333333333
>>> 4.0 / 3
1.3333333333333333
>>> (4.0 / 3).as_integer_ratio()
(6004799503160661, 4503599627370496)
>>> x = Fraction(1, 3)
>>> a = x  + Fraction(*(4.0 / 3).as_integer_ratio())
>>> a
Fraction(22517998136852479, 13510798882111488)
>>> a.limit_denominator(10) #设置分母最大值为10
Fraction(5, 3)

集合(sets):

集合是指一组无序的、不可变的、不重复的数据的集合,支持相应的数学集合运算理论。集合支持一些其他对象的方法,例如列表、字典等,并且集合是可迭代的,并且元素可增可减,可以包含多样的对象类型,集合看起来和字典的键很相似不过支持更多的操作。
不过因为集合是无序的而且不支持键值索引,所以它既不是序列也不是映射类型,而是自成一类,是一种独特的类型。

>>> set([1, 2, 3, 4])
{1, 2, 3, 4}
>>> set('spam')
{'s', 'a', 'p', 'm'}
# Built-in: same as in 2.6
# Add all items in an iterable
>>> {1, 2, 3, 4}
{1, 2, 3, 4}
>>> S = {'s', 'p', 'a', 'm'}
>>> S
{'s', 'a', 'p', 'm'} # Set literals: new in 3.X (and 2.7)
>>> S.add('alot')
>>> S
{'s', 'a', 'p', 'alot', 'm'}
>>> S1 = {1, 2, 3, 4}
>>> S1 & {1, 3}     # Intersection
{1, 3}
>>> {1, 5, 3, 6} | S1   # Union
{1, 2, 3, 4, 5, 6}
>>> S1 - {1, 3, 4}    # Difference 
{2}
>>> S1 > {1, 3}   # Superset
True
>>> {1, 2, 3} | {3, 4}
{1, 2, 3, 4}
>>> {1, 2, 3} | [3, 4]
TypeError: unsupported operand type(s) for |: 'set' and 'list'
>>>
{1,
>>>
{1,
>>>
{1,
{1, 2, 3}.union([3, 4])
2, 3, 4}
{1, 2, 3}.union({3, 4})
2, 3, 4}
{1, 2, 3}.union(set([3, 4]))
2, 3, 4}
>>> {1, 2, 3}.intersection((1, 3, 5))
{1, 3}
>>> {1, 2, 3}.issubset(range(-5, 5))
True

不可变性

集合是一个强大而又灵活的对象,但它也有一个限制,必须铭记在心——它的元素只能是不可变对象,因此列表和字典不能够包含在集合中,但是元组(tuples)可以。

>>> S
{1.23}
>>> S.add([1, 2, 3])
TypeError: unhashable type: 'list'  # Only immutable objects work in a set
Other Numeric Types | 167>>> S.add({'a':1})
TypeError: unhashable type: 'dict'
>>> S.add((1, 2, 3))
>>> S
{1.23, (1, 2, 3)}
>>> S | {(4, 5, 6), (1, 2, 3)}
{1.23, (4, 5, 6), (1, 2, 3)}
>>> (1, 2, 3) in S
True
>>> (1, 4, 3) in S
False

元组包含在集合中,例如可以用来代表数据、记录、IP地址等,集合也可以包含模块、类型对象等。集合本身也是可变的,所以不能内嵌到集合中。但frozenset内置函数工作模式和集合一样,但建立的是不可变对象,无法更改。
当然,集合也支持列表推导式:

>>> {x for x in 'spam'}
{'m', 's', 'p', 'a'} # Same as: set('spam')
>>> {c *
{'pppp',
>>> {c *
{'pppp', # Set of collected expression results
4 for c
'aaaa',
4 for c
'aaaa',
in 'spam'}
'ssss', 'mmmm'}
in 'spamham'}
'hhhh', 'ssss', 'mmmm'}
>>> S = {c * 4 for c in 'spam'}
168 | Chapter 5: Numeric Types>>> S | {'mmmm', 'xxxx'}
{'pppp', 'xxxx', 'mmmm', 'aaaa', 'ssss'}
>>> S & {'mmmm', 'xxxx'}
{'mmmm'}

布尔型

>>> type(True)
<class 'bool'>
>>> isinstance(True, int)
True
>>> True == 1
True
>>> True is 1
False
>>> True or False
True
>>> True + 4
5
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章