数字日期和时间
数字的四舍五入
>>> round(1.23, 1)
1.2
>>> round(1.27, 1)
1.3
>>> round(-1.27, 1)
-1.3
>>> round(1.25, 1)
1.2
>>> round(1.26, 1)
1.3
>>> round(1.5, 0)
2.0
>>> a = 1627731
>>> round(a, -1)
1627730
>>> round(a, -3)
1628000
如果只是为了输出格式化,请不要用round
>>> x = 1.23456
>>> format(x, '0.2f')
'1.23'
如果为了修正计算后的浮点值,请不要使用round
>>> a = 2.1
>>> b = 4.2
>>> a + b
6.300000000000001
执行精确的浮点数运算
>>> from decimal import Decimal
>>> a = Decimal('4.2')
>>> b = Decimal('2.1')
>>> a + b
Decimal('6.3')
>>> (a + b) == Decimal('6.3')
True
>>> 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
数字的格式化输出
输出单个字符
>>> x = 1234.56789
>>> format(x, '0.2f')
'1234.57'
>>> format(x, '>10.1f')
' 1234.6'
>>> format(x, '<10.1f')
'1234.6 '
>>> format(x, '^10.1f')
' 1234.6 '
>>> format(x, ',')
'1,234.56789'
>>> format(x, '0,.1f')
'1,234.6'
>>>
二八十六进制整数
>>> x =1234
>>> bin(x)
'0b10011010010'
>>> oct(x)
'0o2322'
>>> hex(x)
'0x4d2'
# 不要前缀的话,如下:
>>> format(x, 'b')
'10011010010'
>>> format(x, 'o')
'2322'
>>> format(x, 'x')
'4d2'
# 有符号变无符号
>>> x = -1234
>>> format(2*32 + x, 'b')
'-10010010010'
>>> format(2**32 + x, 'b')
'11111111111111111111101100101110'
>>> format(2**32 + x, 'x')
'fffffb2e'
# 不同的进制转换成整数
>>> int('4d2', 16)
1234
>>> int('10011010010', 2)
1234
字节到大整数的打包与解包
# 字节字符串转化成整数:
>>> data = b'\x00\x124V\x00x\x90\xab\x00\xcd\xef\x01\x00#\x004'
>>> len(data)
16
>>> int.from_bytes(data, 'little')
69120565665751139577663547927094891008
>>> int.from_bytes(data, 'big')
94522842520747284487117727783387188
#大整数转化成字节字符串:
>>> x = 94522842520747284487117727783387188
>>> x.to_bytes(16, 'big')
b'\x00\x124V\x00x\x90\xab\x00\xcd\xef\x01\x00#\x004'
>>> x.to_bytes(16, 'little')
b'4\x00#\x00\x01\xef\xcd\x00\xab\x90x\x00V4\x12\x00'
# 使用int.bit_length()决定需要多少个字节存储这个大整数
>>> x.bit_length()
117
>>> n, rem = divmod(x.bit_length(), 8)
>>> if rem:
n += 1
>>> x.to_bytes(n, 'little')
b'4\x00#\x00\x01\xef\xcd\x00\xab\x90x\x00V4\x12'
复数的数学运算
# 两种形式
>>> a = complex(2, 4)
>>> a
(2+4j)
>>> b = 3 - 5j
>>> b
(3-5j)
>>> a.real # 实部
2.0
>>> a.imag # 虚部
4.0
>>> a.conjugate() #共轭复数
(2-4j)
无穷大与NaN
>>> a = float('inf')
>>> b = float('-inf')
>>> c = float('nan')
>>> a #无穷大
inf
>>> b #无穷小
-inf
>>> c #非数字
nan
# 验证
>>> import math
>>> math.isinf(a)
True
>>> math.isnan(c)
True
分数运算
>>> from fractions import Fraction
>>> a = Fraction(5, 4)
>>> b = Fraction(7, 16)
>>> print(a + b)
27/16
>>> c = a * b
>>> c.numerator
35
>>> c.denominator
64
大型数组运算
# 普通的数组运算
>>> 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 "<pyshell#116>", line 1, in <module>
x +10
TypeError: can only concatenate list (not "int") to list
>>> x + y
[1, 2, 3, 4, 5, 6, 7, 8]
# numpy的数组运算
>>> 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])
# numpy还提供了大量的通用函数
>>> np.sqrt(ax)
array([1. , 1.41421356, 1.73205081, 2. ])
>>> np.cos(ax)
array([ 0.54030231, -0.41614684, -0.9899925 , -0.65364362])
矩阵与线性代数运算
>>> import numpy as np
>>> m = np.matrix([[1,-2,3],[0,4,5],[7,8,-9]])
>>> m
matrix([[ 1, -2, 3],
[ 0, 4, 5],
[ 7, 8, -9]])
>>> m.T
matrix([[ 1, 0, 7],
[-2, 4, 8],
[ 3, 5, -9]])
>>> m.I
matrix([[ 0.33043478, -0.02608696, 0.09565217],
[-0.15217391, 0.13043478, 0.02173913],
[ 0.12173913, 0.09565217, -0.0173913 ]])
随机选择
>>> import random
# 随机获取一个元素
>>> values = [1, 2, 3, 4, 5, 6]
>>> random.choice(values)
3
>>> random.choice(values)
1
# 随机获取N个元素
>>> random.sample(values, 2)
[1, 6]
>>> random.sample(values, 2)
[2, 3]
>>> random.sample(values, 3)
[3, 6, 2]
# 打乱序列元素的顺序
>>> random.shuffle(values)
>>> values
[4, 1, 2, 5, 6, 3]
# 生成随机数
>>> random.randint(0, 10) # 获取0-10范围的整数
8
>>> random.random() # 获取0-1范围的浮点数
0.8360116670318987
>>> random.getrandbits(10) # 获取N位(二进制)随机数
971
# random使用Mersenne Twister算法生成随机数,可以修改初始化种子
>>> random.seed() # 基于系统时间
>>> random.seed(12345) # 基于整数
>>> random.seed(b'bytedata') # 基于byte data
基本的日期与时间转换
# 表示时间段
>>> from datetime import timedelta
>>> a = timedelta(days=2, hours=6)
b
>>> b = timedelta(hours=4.5)
>>> c = a + b
>>> c.days
2
>>> c.seconds
37800
>>> c.seconds / 3600
10.5
>>> c.total_seconds() / 3600
58.5
# 表示指定的日期和时间
>>> from datetime import datetime
>>> a = datetime(2012, 9, 23)
>>> print(a + timedelta(days=10))
2012-10-03 00:00:00
>>> b = datetime(2012, 12, 21)
>>> d = b - a
>>> d.days
89
>>> d
datetime.timedelta(days=89)
>>> now = datetime.today()
>>> print(now)
2022-05-13 16:38:55.123458
>>> print(now + timedelta(minutes=10))
2022-05-13 16:48:55.123458
# datetime会自动处理闰年
>>> a = datetime(2012, 3, 1)
>>> b = datetime(2012, 2, 28)
>>> a - b
datetime.timedelta(days=2)
>>> a = datetime(2013, 3, 1)
>>> b = datetime(2013, 2, 28)
>>> a - b
datetime.timedelta(days=1)
# 如果要处理时区,模糊时间范围,节假日等计算
>>> from dateutil.relativedelta import relativedelta
>>> from datetime import datetime
>>> a = datetime(2012, 9, 23)
>>> a + relativedelta(months=+1)
datetime.datetime(2012, 10, 23, 0, 0)
>>> a + relativedelta(months=+4)
datetime.datetime(2013, 1, 23, 0, 0)
>>> b = datetime(2012, 12, 21)
>>> b - a
datetime.timedelta(days=89)
>>> relativedelta(b, a)
relativedelta(months=+2, days=+28)
>>> relativedelta(b, a).days
28
>>> relativedelta(b, a).months
2
计算一个周五的日期
# 通用做法是将起始和目标日期映射到星期数组,然后用%7的余数来判断
# 也可以直接用如下方法
>>> from dateutil.rrule import *
>>> d = datetime.now()
>>> print(d)
2022-05-17 10:47:00.718425
>>> print(d + relativedelta(weekday=FR))
2022-05-20 10:47:00.718425
>>> print(d + relativedelta(weekday=FR(-1)))
2022-05-13 10:47:00.718425
计算当前月份的日期范围
>>> from datetime import datetime, date, timedelta
>>> import calendar
>>> def get_month_range(start_date=None):
if start_date is None:
start_date = 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)
>>> a_day = timedelta(days=1)
>>> first_day, last_day = get_month_range()
>>> while first_day < last_day:
print(first_day)
first_day += a_day
2022-05-01
2022-05-02
2022-05-03
2022-05-04
2022-05-05
# 可以再创建一个新的类似range()的函数
>>> def date_range(start, stop, step):
while start < stop:
yield start
start += step
>>> for d in date_range(datetime(2012, 9, 1), datetime(2012, 10, 1),
timedelta(hours=6)):
print(d)
2012-09-01 00:00:00
2012-09-01 06:00:00
2012-09-01 12:00:00
2012-09-01 18:00:00
2012-09-02 00:00:00
2012-09-02 06:00:00
......
字符串转换为日期
# 字符串转换成日期
>>> from datetime import datetime
>>> text = '2012-09-20'
>>> y = datetime.strptime(text, '%Y-%m-%d')
>>> y
datetime.datetime(2012, 9, 20, 0, 0)
>>> z = datetime.now()
>>> z - y
datetime.timedelta(days=3526, seconds=50876, microseconds=21114)
#日期转换成自定义的格式
>>> z
datetime.datetime(2022, 5, 17, 14, 7, 56, 21114)
>>> nice_z = datetime.strftime(z, '%A %B %d, %Y')
>>> nice_z
'Tuesday May 17, 2022'
# strptime的性能很差,如果要解析大量日期且已经知道了日期格式是YYYY-MM-DD
# 可以如下实现
>>> 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))
>>> ymd = parse_ymd('2022-05-17')
>>> ymd
datetime.datetime(2022, 5, 17, 0, 0)
结合时区的日期操作
# 首先将日期对象本地化,比如表示芝加哥时间
>>> from pytz import timezone
>>> d = datetime(2012, 12, 21, 9, 30, 0)
>>> print(d)
2012-12-21 09:30:00
>>> central = timezone('US/Central')
>>> loc_d = central.localize(d)
>>> print(loc_d)
2012-12-21 09:30:00-06:00
#本地化后就可以转化成其他时区的时间,比如班加罗尔
>>> bang_d = loc_d.astimezone(timezone('Asia/Kolkata'))
>>> print(bang_d)
2012-12-21 21:00:00+05:30
# 如果使用本地化时间进行计算,还要特别注意夏令时和其他细节
# 所以通常策略是将所有日期转换为UTC时间
>>> import pytz
>>> print(loc_d)
2012-12-21 09:30:00-06:00
>>> utc_d = loc_d.astimezone(pytz.utc)
>>> print(utc_d)
2012-12-21 15:30:00+00:00
# 如何得到时区的名称,可以使用ISO 3166国家代码作为关键字查找
>>> pytz.country_timezones['IN']
['Asia/Kolkata']