2022-5-11 python cookbook(v3.0) 学习笔记(三)

数字日期和时间

数字的四舍五入

>>> 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']
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值