此文仅为学习python cookbook书籍时候记的笔记,记录过程权当加深记忆,无任何主观内容,若需参考可直接至此在线文档学习。
数字的四舍五入
round(value, ndigits)
1
2
3
4
5
6
7
8
9>>> round(1.23, 1)
1.2
>>> round(1.27, 1)
1.3
>>> round(-1.27, 1)
-1.3
>>> round(1.25361,3)
1.254
>>>
当一个值刚好在两个边界的中间的时候, round 函数返回离它最近的偶数。 也就是说,对1.5或者2.5的舍入运算都会得到2。
传给 round() 函数的 ndigits 参数可以是负数1
2
3
4
5
6
7
8>>> a = 1627731
>>> round(a, -1)
1627730
>>> round(a, -2)
1627700
>>> round(a, -3)
1628000
>>>
如果你的目的只是简单的输出一定宽度的数,你不需要使用 round() 函数。 而仅仅只需要在格式化的时候指定精度即可。1
2
3
4
5
6
7
8 >>> x = 1.23456
>>> format(x, '0.2f')
'1.23'
>>> format(x, '0.3f')
'1.235'
>>> 'value is {:0.3f}'.format(x)
'value is 1.235'
>>>
执行精确的浮点数运算
浮点数的一个普遍问题是它们并不能精确的表示十进制数。 并且,即使是最简单的数学运算也会产生小的误差。1
2
3
4
5
6
7 >>> a = 4.2
>>> b = 2.1
>>> a + b
6.300000000000001
>>> (a + b) == 6.3
False
>>>
decimal
模块1
2
3
4
5
6
7
8
9 >>> from decimal import Decimal
>>> a = Decimal('4.2')
>>> b = Decimal('2.1')
>>> a + b
Decimal('6.3')
>>> print(a + b)
6.3
>>> (a + b) == Decimal('6.3')
True
decimal 模块的一个主要特征是允许你控制计算的每一方面,包括数字位数和四舍五入运算。 为了这样做,你先得创建一个本地上下文并更改它的设置。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16>>> from decimal import localcontext
>>> a = Decimal('1.3')
>>> b = Decimal('1.7')
>>> print(a / b)
0.7647058823529411764705882353
>>> with localcontext() as ctx:
... ctx.prec = 3
... print(a / b)
...
0.765
>>> with localcontext() as ctx:
... ctx.prec = 50
... print(a / b)
...
0.76470588235294117647058823529411764705882352941176
>>>
浮点数运算也不能完全忽略误差,如:1
2
3
4>>> nums = [1.23e+18, 1, -1.23e+18]
>>> sum(nums) # Notice how 1 disappears
0.0
>>>
可以用math.fsum()
所提供的更精确计算能力来解决:1
2
3
4>>> import math
>>> math.fsum(nums)
1.0
>>>
数字的格式化输出
格式化输出单个数字的时候,可以使用内置的 format() 函数1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24>>> x = 1234.56789
>>> # Two decimal places of accuracy
>>> format(x, '0.2f')
'1234.57'
>>> # Right justified in 10 chars, one-digit accuracy
>>> format(x, '>10.1f')
' 1234.6'
>>> # Left justified
>>> format(x, '<10.1f')
'1234.6 '
>>> # Centered
>>> format(x, '^10.1f')
' 1234.6 '
>>> # Inclusion of thousands separator
>>> format(x, ',')
'1,234.56789'
>>> format(x, '0,.1f')
'1,234.6'
>>>
当指定数字的位数后,结果值会根据 round() 函数同样的规则进行四舍五入后返回。1
2
3
4
5
6
7>>> x
1234.56789
>>> format(x, '0.1f')
'1234.6'
>>> format(-x, '0.1f')
'-1234.6'
>>>
同时指定宽度和精度的一般形式是 ‘[<>^]?width[,]?(.digits)?’ , 其中 width 和 digits 为整数,?代表可选部分。 同样的格式也被用在字符串的 format() 方法中。1
2
3>>> 'The value is {:0,.2f}'.format(x)
'The value is 1,234.57'
>>>
在很多Python代码中会看到使用%来格式化数字的1
2
3
4
5
6
7>>> '%0.2f' % x
'1234.57'
>>> '%10.1f' % x
' 1234.6'
>>> '%-10.1f' % x
'1234.6 '
>>>
二八十六进制整数
bin()
, oct()
或hex()
函数1
2
3
4
5
6
7>>> x = 1234
>>> bin(x)
'0b10011010010'
>>> oct(x)
'0o2322'
>>> hex(x)
'0x4d2'
另外,如果你不想输出 0b , 0o 或者 0x 的前缀的话,可以使用 format() 函数。1
2
3
4
5
6>>> format(x, 'b')
'10011010010'
>>> format(x, 'o')
'2322'
>>> format(x, 'x')
'4d2'
整数是有符号的,所以如果你在处理负数的话,输出结果会包含一个负号。1
2
3
4
5>>> x = -1234
>>> format(x, 'b')
'-10011010010'
>>> format(x, 'x')
'-4d2'
字节到大整数的打包与解包
int.from_bytes()
data = b’\x00\x124V\x00x\x90\xab\x00\xcd\xef\x01\x00#\x004’
1 | >>> len(data) |
1 | >>> x = 94522842520747284487117727783387188 |
complex(real, imag)
1
2
3
4
5
6
7>>> a = complex(2, 4)
>>> b = 3 - 5j
>>> a
(2+4j)
>>> b
(3-5j)
>>>
对应的实部、虚部和共轭复数可以很容易的获取。1
2
3
4
5
6
7>>> a.real
2.0
>>> a.imag
4.0
>>> a.conjugate()
(2-4j)
>>>
1 | >>> a + b |
复数的数学运算
complex(real, imag)
1
2
3
4
5
6
7>>> a = complex(2, 4)
>>> b = 3 - 5j
>>> a
(2+4j)
>>> b
(3-5j)
>>>
对应的实部、虚部和共轭复数可以很容易的获取。1
2
3
4
5
6
7>>> a.real
2.0
>>> a.imag
4.0
>>> a.conjugate()
(2-4j)
>>>
另外,所有常见的数学运算都可以工作(+-*/)
如果要执行其他的复数函数比如正弦、余弦或平方根,使用 cmath 模块1
2
3
4
5
6
7
8>>> import cmath
>>> cmath.sin(a)
(24.83130584894638-11.356612711218174j)
>>> cmath.cos(a)
(-11.36423470640106-24.814651485634187j)
>>> cmath.exp(a)
(-4.829809383269385-5.5920560936409816j)
>>>
Python中大部分与数学相关的模块都能处理复数。 比如如果你使用 numpy ,可以很容易的构造一个复数数组并在这个数组上执行各种操作1
2
3
4
5
6
7
8
9>>> import numpy as np
>>> a = np.array([2+3j, 4+5j, 6-7j, 8+9j])
>>> a
array([ 2.+3.j, 4.+5.j, 6.-7.j, 8.+9.j])
>>> a + 2
array([ 4.+3.j, 6.+5.j, 8.-7.j, 10.+9.j])
>>> np.sin(a)
array([ 9.15449915 -4.16890696j, -56.16227422 -48.50245524j,
-153.20827755-526.47684926j, 4008.42651446-589.49948373j])
如果你想生成一个复数返回结果,你必须显示的使用 cmath 模块1
2
3>>> import cmath
>>> cmath.sqrt(-1)
1j
无穷大与NaN
创建或测试正无穷、负无穷或NaN(非数字)的浮点数。
Python并没有特殊的语法来表示这些特殊的浮点值,但是可以使用 float() 来创建它们。1
2
3
4
5
6
7
8
9
10>>> a = float('inf')
>>> b = float('-inf')
>>> c = float('nan')
>>> a
inf
>>> b
-inf
>>> c
nan
>>>
为了测试这些值的存在,使用 math.isinf() 和 math.isnan() 函数。1
2
3
4>>> math.isinf(a)
True
>>> math.isnan(c)
True
无穷大数在执行数学计算的时候会传播1
2
3
4
5
6
7
8>>> a = float('inf')
>>> a + 45
inf
>>> a * 10
inf
>>> 10 / a
0.0
>>>
NaN值会在所有操作中传播,而不会产生异常。1
2
3
4
5
6
7
8
9
10>>> c = float('nan')
>>> c + 23
nan
>>> c / 2
nan
>>> c * 2
nan
>>> math.sqrt(c)
nan
>>>
测试: math.isnan()
分数运算
1 |
|
大型数组运算
涉及到数组的重量级运算操作,可以使用 NumPy 库。 NumPy 的一个主要特征是它会给Python提供一个数组对象,相比标准的Python列表而已更适合用来做数学运算。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25>>> # Python lists
>>> x = [1, 2, 3, 4]
>>> y = [5, 6, 7, 8]
>>> x * 2
[1, 2, 3, 4, 1, 2, 3, 4]
>>> x + 10
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: can only concatenate list (not "int") to list
>>> x + y
[1, 2, 3, 4, 5, 6, 7, 8]
>>> # Numpy arrays
>>> import numpy as np
>>> ax = np.array([1, 2, 3, 4])
>>> ay = np.array([5, 6, 7, 8])
>>> ax * 2
array([2, 4, 6, 8])
>>> ax + 10
array([11, 12, 13, 14])
>>> ax + ay
array([ 6, 8, 10, 12])
>>> ax * ay
array([ 5, 12, 21, 32])
>>>
NumPy 中的标量运算(比如 ax * 2 或 ax + 10 )会作用在每一个元素上。另外,当两个操作数都是数组的时候执行元素对等位置计算,并最终生成一个新的数组。1
2
3
4
5
6
7
8```
>>> def f(x):
... return 3*x**2 - 2*x + 7
...
>>> f(ax)
array([ 8, 15, 28, 47])
>>>
NumPy 还为数组操作提供了大量的通用函数,这些函数可以作为 math 模块中类似函数的替代。
np.sqrt(ax)
array([ 1. , 1.41421356, 1.73205081, 2. ])
np.cos(ax)
array([ 0.54030231, -0.41614684, -0.9899925 , -0.65364362])
1 如果你想构造一个10,000*10,000的浮点数二维网格grid = np.zeros(shape=(10000,10000), dtype=float)
grid
array([[ 0., 0., 0., …, 0., 0., 0.],
[ 0., 0., 0., …, 0., 0., 0.],
[ 0., 0., 0., …, 0., 0., 0.],
…,
[ 0., 0., 0., …, 0., 0., 0.],
[ 0., 0., 0., …, 0., 0., 0.],
[ 0., 0., 0., …, 0., 0., 0.]])
1 所有的普通操作还是会同时作用在所有元素上:a = np.array([[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]])
a
array([[ 1, 2, 3, 4],
[ 5, 6, 7, 8],
[ 9, 10, 11, 12]])Select row 1
a[1]
array([5, 6, 7, 8])Select column 1
a[:,1]
array([ 2, 6, 10])Select a subregion and change it
a[1:3, 1:3]
array([[ 6, 7],
[10, 11]])
a[1:3, 1:3] += 10
a
array([[ 1, 2, 3, 4],
[ 5, 16, 17, 8],
[ 9, 20, 21, 12]])Broadcast a row vector across an operation on all rows
a + [100, 101, 102, 103]
array([[101, 103, 105, 107],
[105, 117, 119, 111],
[109, 121, 123, 115]])
a
array([[ 1, 2, 3, 4],
[ 5, 16, 17, 8],
[ 9, 20, 21, 12]])Conditional assignment on an array
np.where(a < 10, a, 10)
array([[ 1, 2, 3, 4],
[ 5, 10, 10, 8],
[ 9, 10, 10, 10]])
1
2 ### 随机选择
random 模块有大量的函数用来产生随机数和随机选择元素。import random
values = [1, 2, 3, 4, 5, 6]
random.choice(values)
2
random.choice(values)
3
random.choice(values)
1
random.choice(values)
4
random.choice(values)
6
1 为了提取出N个不同元素的样本用来做进一步的操作,可以使用` random.sample()`random.sample(values, 2)
[6, 2]
random.sample(values, 2)
[4, 3]
random.sample(values, 3)
[4, 3, 1]
random.sample(values, 3)
[5, 4, 1]
1 如果你仅仅只是想打乱序列中元素的顺序, 可以使用 `random.shuffle()`random.shuffle(values)
values
[2, 4, 6, 5, 3, 1]
random.shuffle(values)
values
[3, 5, 2, 1, 6, 4]
1 生成随机整数,请使用 random.randint()random.randint(0,10)
2
random.randint(0,10)
5
random.randint(0,10)
0
random.randint(0,10)
7
random.randint(0,10)
10
random.randint(0,10)
3
1 为了生成0到1范围内均匀分布的浮点数random.random()
0.9406677561675867
random.random()
0.133129581343897
random.random()
0.4144991136919316
1 如果要获取N位随机位(二进制)的整数,使用 random.getrandbits()random.getrandbits(200)
335837000776573622800628485064121869519521710558559406913275
1 random 模块使用 Mersenne Twister 算法来计算生成随机数。
random.seed() # Seed based on system time or os.urandom()
random.seed(12345) # Seed based on integer given
random.seed(b’bytedata’) # Seed based on byte data1
2
3
4random模块还包含基于均匀分布、高斯分布和其他分布的随机数生成函数。 比如, random.uniform() 计算均匀分布随机数, random.gauss() 计算正态分布随机数。
> 在 random 模块中的函数不应该用在和密码学相关的程序中。如需,ssl.RAND_bytes() 可以用来生成一个安全的随机字节序列。
### 基本的日期与时间转换
为了执行不同时间单位的转换和计算,请使用 datetime 模块。 比如,为了表示一个时间段,可以创建一个 timedelta 实例。
from datetime import timedelta
a = timedelta(days=2, hours=6)
b = timedelta(hours=4.5)
c = a + b
c.days
2
c.seconds # 包括小时数后的分数
37800
c.seconds / 3600 # 10.5小时
10.5
c.total_seconds() / 3600 #总小时数
58.5
1 如果你想表示指定的日期和时间,先创建一个 datetime 实例然后使用标准的数学运算来操作它们。from datetime import datetime
a = datetime(2012, 9, 23)
print(a + timedelta(days=10))
2012-10-03 00:00:00b = datetime(2012, 12, 21)
d = b - a
d.days
89
now = datetime.today()
print(now)
2012-12-21 14:54:43.094063
print(now + timedelta(minutes=10))
2012-12-21 15:04:43.094063
1 在计算的时候,需要注意的是 datetime 会自动处理闰年。a = datetime(2012, 3, 1)
b = datetime(2012, 2, 28)
a - b
datetime.timedelta(2)
(a - b).days
2
c = datetime(2013, 3, 1)
d = datetime(2013, 2, 28)
(c - d).days
1
1
2 对大多数基本的日期和时间处理问题, datetime 模块以及足够了。
许多类似的时间计算可以使用`dateutil.relativedelta() `函数代替。但是,有一点需要注意的就是,它会在处理月份(还有它们的天数差距)的时候填充间隙。a = datetime(2012, 9, 23)
a + timedelta(months=1)
Traceback (most recent call last):
File ““, line 1, in
TypeError: ‘months’ is an invalid keyword argument for this functionfrom dateutil.relativedelta import relativedelta
a + relativedelta(months=+1)
datetime.datetime(2012, 10, 23, 0, 0)
a + relativedelta(months=+4)
datetime.datetime(2013, 1, 23, 0, 0)Time between two dates
b = datetime(2012, 12, 21)
d = b - a
d
datetime.timedelta(89)
d = relativedelta(b, a)
d
relativedelta(months=+2, days=+28)
d.months
2
d.days
28
1
2 ### 计算当前月份的日期范围
使用 `calendar.monthrange`函数来找出该月的总天数。任何时候只要你想获得日历信息,那么 calendar 模块就非常有用了。
from datetime import datetime, date, timedelta
import calendar
def get_month_range(start_date=None):
if start_date is None:
startdate = date.today().replace(day=1)
, days_in_month = calendar.monthrange(start_date.year, start_date.month)
end_date = start_date + timedelta(days=days_in_month)
return (start_date, end_date)1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17```
>>> a_day = timedelta(days=1)
>>> first_day, last_day = get_month_range()
>>> while first_day < last_day:
... print(first_day)
... first_day += a_day
...
2012-08-01
2012-08-02
2012-08-03
2012-08-04
2012-08-05
2012-08-06
2012-08-07
2012-08-08
2012-08-09
#... and so on...
字符串转换为日期
1 | >>> from datetime import datetime |
datetime.strptime() 方法支持很多的格式化代码, 比如 %Y 代表4位数年份, %m 代表两位数月份。1
2
3
4
5
6>>> z
datetime.datetime(2012, 9, 23, 21, 37, 4, 177393)
>>> nice_z = datetime.strftime(z, '%A %B %d, %Y')
>>> nice_z
'Sunday September 23, 2012'
>>>
strptime() 的性能要比你想象中的差很多, 因为它是使用纯Python实现,并且必须处理所有的系统本地设置。
1
2
3
4 from datetime import datetime
def parse_ymd(s):
year_s, mon_s, day_s = s.split('-')
return datetime(int(year_s), int(mon_s), int(day_s))