Python实战之数字日期和时间的高级处理
Posted 山河已无恙
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Python实战之数字日期和时间的高级处理相关的知识,希望对你有一定的参考价值。
写在前面
- 博文为《Python Cookbook》读书后笔记整理
- 涉及内容包括:
- 浮点数执行指定精度的舍入运算。
- 执行精确的浮点数运算
- 数字的格式化输出
- 对数值进行取整
- 二进制、八进制和十六进制整数转化输出
- 从字节串中打包和解包大整数
- 复数的数学运算
- 处理无穷大和NaN
- 处理大型数组的计算
- 矩阵和线性代数的计算
- 计算当前日期做后一个星期几的日期
- 找出当月的日期范围
- 将字符串转换为日期
- 处理涉及到时区的日期问题
- 理解不足小伙伴帮忙指正
傍晚时分,你坐在屋檐下,看着天慢慢地黑下去,心里寂寞而凄凉,感到自己的生命被剥夺了。当时我是个年轻人,但我害怕这样生活下去,衰老下去。在我看来,这是比死亡更可怕的事。--------王小波
数字、日期和时间的高级处理
嗯,学习发现有些方法函数即使大版本相同,小版本也是有些差距的,这是我学习的版本
┌──[root@liruilongs.github.io]-[~]
└─$python3
Python 3.6.8 (default, Nov 16 2020, 16:55:22)
[GCC 4.8.5 20150623 (Red Hat 4.8.5-44)] on linux
Type "help", "copyright", "credits" or "license" for more information.
浮点数执行指定精度的舍入运算。
对浮点数执行指定精度的舍入运算。
对于简单的舍入运算,使用内置的round(value, ndigits)
函数即可。
┌──[root@liruilongs.github.io]-[~]
└─$python3
Python 3.6.8 (default, Nov 16 2020, 16:55:22)
[GCC 4.8.5 20150623 (Red Hat 4.8.5-44)] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> round(1.23, 1)
1.2
>>> round(1.25361,3)
1.254
>>>
当一个值刚好在两个边界的中间的时候, round 函数返回离它最近的偶数。对 1.5 或者 2.5 的舍入运算都会得到 2。
>>> round(1.5,0)
2.0
>>> round(2.5,0)
2.0
>>>
传给 round()
函数的 ndigits 参数可以是负数,舍入运算会作用在十位、百位、千位等上面
>>> a = 1627731
>>> round(a, -1)
1627730
>>> round(a, -2)
1627700
>>>
不要将舍入和格式化输出
搞混淆了。如果你的目的只是简单的输出一定宽度的数,你不需要使用round()
函数。而仅仅只需要在格式化的时候指定精度即可,
>>> x = 1.23456
>>> format(x, '0.2f')
'1.23'
>>> format(x, '0.4f')
'1.2346'
>>> 'value is :0.3f'.format(x)
'value is 1.235'
>>>
可以看到,输出的数据并不相同,一个是字符串,一个是int等数字类型
>>> type(format(1.5, '0.0f'))
<class 'str'>
>>> type(round(a, -1))
<class 'int'>
>>> type(round(1.25361,3))
<class 'float'>
>>>
不要试着去舍入浮点值来” 修正” 表面上看起来正确的问题。大多数使用到浮点的程序,没有必要也不推荐这样做.
>>> 2.1 + 4.2
6.300000000000001
>>> round(2.1 + 4.2,2)
6.3
>>>
执行精确的浮点数运算
要对浮点数执行精确的计算操作,并且不希望有任何小误差的出现。
浮点数的一个普遍问题是它们并不能精确的表示十进制数。并且,即使是最简单的数学运算也会产生小的误差
就那上面的Demo来讲
>>> 2.1 + 4.2
6.300000000000001
>>> round(2.1 + 4.2,2)
6.3
>>> (2.1 + 4.2) == 6.3
False
>>>
错误是由底层 CPU 和 IEEE 754 标准
通过自己的浮点单位去执行算术
时的特征。由于 Python 的浮点数据类型使用底层表示存储数据
,因此你没办法去避免这样的误差。在Java里也出现同样的问题
public static void main(String[] args)
System.out.println(2.1+4.2);
// 6.300000000000001
如果你想更加精确 (并能容忍一定的性能损耗),你可以使用 decimal 模块
>>> 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 模块的一个主要特征是允许你控制计算的每一方面
,包括数字位数和四舍五入运算
。为了这样做,你先得创建一个本地上下文并更改它的设置
>>> 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
>>>
decimal 模块
实现了 IBM 的” 通用小数运算规范”,Python 新手会倾向于使用 decimal 模块
来处理浮点数的精确运算。但是要根据业务需求来处理,decimal 模块主要用在涉及到金融的领域。
- 原生的浮点数计算要快的多
- 在真实世界中很少会要求精确到普通浮点数能提供的 17 位精度
其他的一些误差,大数和小数的加法运算(在Java里也出现同样的问题)
>>> nums = [1.23e+18, 1, -1.23e+18]
>>> sum(nums)
0.0
>>> 1.23e+18 + 1 + -1.23e+18
0.0
>>> 1.23e+18 + -1.23e+18 + 1
1.0
>>>
public static void main(String[] args)
System.out.println(1.23e+18 + 1 + -1.23e+18);
// 0.0
py的解决办法
>>> import math
>>> math.fsum(nums)
1.0
>>>
数字的格式化输出
你需要将数字格式化后输出,并控制数字的位数、对齐、千位分隔符和其他的细节。
格式化输出单个数字的时候,可以使用内置的format()
函数,这个前面也有好的Demo,不多说
>>> x = 1234.56789
>>> format(x, '0.2f')
'1234.57'
>>> format(x, '>10.1f')
' 1234.6'
>>> format(x, '<10.1f')
'1234.6 '
>>> format(x, '0>10.1f')
'00001234.6'
>>> format(x, '^10.1f')
' 1234.6 '
>>> format(x, ',')
'1,234.56789'
>>> format(x, '0,.1f')
'1,234.6'
>>>
使用指数
记法,将 f 改成 e 或者 E(取决于指数输出的大小写形式)
。
>>> format(x, 'e')
'1.234568e+03'
>>> format(x, '0.2E')
'1.23E+03'
>>>
同时指定宽度和精度
的一般形式是 '[<>ˆ]?width[,]?(.digits)?'
,其中 width 和 digits 为整数,?代表可选部分。
同样的格式也被用在字符串
的format()
方法中。
>>> 'The value is :0,.2f'.format(x)
'The value is 1,234.57'
>>>
format() 函数 同时适用于浮点数和 decimal模块中的 Decimal 数字对象。
>>> x
1234.56789
>>> format(x, '0.1f')
'1234.6'
>>> format(-x, '0.1f')
'-1234.6'
>>>
包含千位符的格式化跟本地化没有关系。如果你需要根据地区来显示千位符,你需要自己去调查下 locale 模块中的函数了。你同样也
可以使用字符串的 translate()方法来交换千位符。
>>> swap_separators = ord('.'):',', ord(','):'.'
>>> format(x, ',').translate(swap_separators)
'1.234,56789'
>>> x
1234.56789
>>>
也可以直接使用%
来格式化数字的
>>> x
1234.56789
>>> '%0.2f' % x
'1234.57'
>>> '%10.1f' % x
' 1234.6'
>>> '%-10.1f' % x
'1234.6 '
二进制、八进制和十六进制整数转化输出
转换或者输出使用二进制,八进制或十六进制表示的整数。
为了将整数
转换为二进制、八进制或十六进制
的文本串
,可以分别使用bin() ,oct() 或 hex()
函数:
>>> x = 1234
>>> bin(x)
'0b10011010010'
>>> oct(x)
'0o2322'
>>> hex(x)
'0x4d2'
>>>
不想输出 0b , 0o 或者 0x 的前缀的话,可以使用format()
函数
>>> format(x, 'b')
'10011010010'
>>> format(x, 'o')
'2322'
>>> format(x, 'x')
'4d2'
>>>
整数是有符号的,所以如果你在处理负数的话,输出结果会包含一个负号
>>> x = -1234
>>> format(x, 'b')
'-10011010010'
>>> format(x, 'x')
'-4d2'
>>>
如果你想产生一个无符号值,你需要增加一个指示最大位长度的值。比如为了显示32 位的值,
>>> x = -1234
>>> format(2**32 + x, 'b')
'11111111111111111111101100101110'
>>> format(2**32 + x, 'x')
'fffffb2e'
>>>
为了以不同的进制转换整数字符串,简单的使用带有进制的int()
函数即可:
>>> int('4d2', 16)
1234
>>> int('10011010010', 2)
1234
>>>
Python 指定八进制数的语法跟其他语言稍有不同
>>> import os
>>> os.chmod('script.py', 0755)
File "<stdin>", line 1
os.chmod('script.py', 0755)
^
SyntaxError: invalid token
>>> os.chmod('app.py', 0o755)
>>
字节字符串到大整数的相互转化
你有一个字节字符串并想将它解压成一个整数。或者,你需要将一个大整数转换为一个字节字符串。
大整数和字节字符串之间的转换操作并不常见,一些场景也会用到,IPv6 网络地址
使用一个 128 位
的整数表示。如果你要从一个数据记录中提取这样的值的时候
处理一个拥有 128 位长的 16 个元素的字节字符串
>>> 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
>>>
为了将一个大整数转换为一个字节字符串,使用int.to_bytes()
方法,并像下面这样指定字节数和字节顺序:
>>> 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'
>>>
这里字节顺序规则 (little 或 big
) 仅仅指定了构建整数时的字节的低位高位排列方式
。
>>> x = 0x01020304
>>> x.to_bytes(4, 'big')
b'\\x01\\x02\\x03\\x04'
>>> x.to_bytes(4, 'little')
b'\\x04\\x03\\x02\\x01'
>>>
如果你试着将一个整数打包为字节字符串
,那么它就不合适了,你会得到一个错误
。如果需要的话,你可以使用 int.bit_length()
方法来决定需要多少字节位来存储这个值
。(** 表示乘方,divmod() 函数把除数和余数运算结果结合起来,返回一个包含商和余数的元组(a // b, a % b)。)
>>> x = 523 ** 23
>>> x
335381300113661875107536852714019056160355655333978849017944067
>>> x.to_bytes(16, 'little')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
OverflowError: int too big to convert
>>> x.bit_length()
208
>>> nbytes, rem = divmod(x.bit_length(), 8)
>>> if rem:
... nbytes += 1
...
>>>
>>> x.to_bytes(nbytes, 'little')
b'\\x03X\\xf1\\x82iT\\x96\\xac\\xc7c\\x16\\xf3\\xb9\\xcf\\x18\\xee\\xec\\x91\\xd1\\x98\\xa2\\xc8\\xd9R\\xb5\\xd0'
>>>
复数的数学运算
使用复数来执行一些计算操作。
复数可以用使用函数complex(real, imag)
或者是带有后缀j
的浮点数来指定。
>>> a = complex(2, 4)
>>> b = 3 - 5j
>>> a
(2+4j)
>>> b
(3-5j)
>>>
对应的实部、虚部和共轭复数可以很容易的获取。
>>> a.real
2.0
>>> a.imag
4.0
>>> a.conjugate()
(2-4j)
>>>
常见的数学四则运算
>>> a + b
(5-1j)
>>> a * b
(26+2j)
>>> a / b
(-0.4117647058823529+0.6470588235294118j)
>>> abs(a)
4.47213595499958
>>>
如果要执行其他的复数函数比如正弦、余弦或平方根
,使用 cmath 模块
:
>>> 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
很容易的构造一个复数数组并在这个数组上执行各种操作
>>> 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])
>>>
Python 的标准数学函数确实情况下并不能产生复数值,因此你的代码中不可能会出现复数返回值
>>> import math
>>> math.sqrt(-1)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: math domain error
>>>
如果你想生成一个复数返回结果,你必须显示的使用 cmath 模块
>>> import cmath
>>> cmath.sqrt(-1)
1j
>>>
处理无穷大和NaN
你想创建或测试正无穷、负无穷或 NaN(非数字) 的浮点数。
Python 并没有特殊的语法来表示这些特殊的浮点值,但是可以使用float()
来创建它们。比如:
>>> a = float('inf')
>>> b = float('-inf')
>>> c = float('nan')
>>> a
inf
>>> b
-inf
>>> c
nan
>>>
使用 math.isinf() 和 math.isnan()
函数来测试
>>> math.isinf(a)
True
>>> math.isnan(c)
True
>>>
无穷大数在执行数学计算的时候会传播
>>> a = float('inf')
>>> a + 45
inf
>>> a * 10
inf
>>> 10 / a
0.0
>>>
有些操作时未定义的并会返回一个 NaN
结果
>>> a = float('inf')
>>> a/a
nan
>>> b = float('-inf')
>>> a Pandas高级教程之:时间处理
举办“Python人工智能之Pytorch深度学习高级实战”远程直播研修班的通知
python实战技巧之两个不等长列表让里面的数字一一对应地相加
python实战技巧之两个列表实例中,如何让里面的数字一一对应地相加对于两个列表是等长的情况