Python常用内置模块

Python内置了很多模块,这些模块往往很有用.

处理时间和日期–datetime

1.获取当前的时间–以datetime对象方式返回

1
2
3
4
5
6
from datetime import datetime
now = datetime.now()
//now 是一个datetime对象
//datetime.datetime(2017, 3, 30, 1, 53, 42, 679114)
print(now)
//2017-03-30 01:53:42.679114

2.获取指定时间和日期,直接像构造一个datetime对象就行了.

1
2
3
time = datetime(2018,4,10,13,21,0)
print(time)
//2018-04-10 13:21:00

3.时间戳

为了解决不同时区的时间不同的问题,时间戳成为了统一全球的时间表达方式,并且,这也成为了计算机保存时间的统一方式.

至于时间戳为什么能够达到统一,来看这个例子.

1
2
timestamp = 0 = 1970-1-1 00:00:00 UTC+0:00 //标准时间
timestamp = 0 = 1970-1-1 08:00:00 UTC+8:00 //北京时间

所以说,timestamp和时区根本就没有关系,只要timestamp定下来,其UTC时间就定下来了,转换到任意时区的时间也是完全固定的.在时间校准的情况下,全球各地的计算机在任意时刻的时间戳都是相同的.

将一个datetime对象转换为时间戳形式很简单.

直接调用timestamp()来构造一个浮点型的时间戳.

注意:Python中的timestamp是一个浮点数,小数是指毫秒,你也许会问,为什么在JAVA,JavaScript中的时间戳是整数呢? 事实上,这些编程语言已经将其乘了1000.所以在表示时要注意进行转换.

反过来,将一个timestamp转换成为datetime只要调用datetime的fromtimestamp()方法即可.

4.字符串与时间的计算和转换

转换的过程事实上是相似的,如同其他语言,都要使用格式化符号来表示年份,星期,月,日和具体的时间.

字符串转datetime

1
2
3
cday = datetime.strptime('2018-6-1 18:19:59', '%Y-%m-%d %H:%M:%S')
print(cday)
//2018-06-01 18:19:59

datetime转字符串

1
2
3
current = now.strftime("%a, %b %d %H:%M")
print(current)
//Thu March 30 02:55

官方文档:时间 格式化符号参考

时间的加减

由于计算机是使用的时间戳来存储的时间,那么就可用+-来进行运算.

但是,如果为了更好地迁移,可以使用这样的模块timedelta.

例如:

1
2
3
4
5
from datetime import datetime, timedelta, timezone
now = datetime.now()
now + timedelta(hours=14)
now + timedelta(days=1)
now + timedelta(days=2,hours=12)//这些都是可行的

你会发现,我多import进来了一个timezone.
这个部件可将时间进行UTC时间的转换.

如:

1
2
3
4
zone = timezone(timedelta(hours=8))
now = datetime.now()
time = now.replace(tzinfo=zone) //就是timezone info啦
time //强制设为UTC+8h

如果需要UTC时间,可以直接调用datetime.utcnow()

交换时区除了通过datetime对象的replace方法强制更改外,带有时区属性的datetime通过astimezone()方法,来进行转换.

比如:

1
2
3
4
5
6
utc_dt = datetime.utcnow().replace(tzinfo=timezone.utc)
print(utc_dt)
//2017-03-29 18:55:04.681162+00:00
bj_dt = utc_dt.astimezone(timezone(timedelta(hours=8)))
print(bj_dt)
//2017-03-29 18:56:22.085203+08:00

如果在获取datetime对象时,没有指定时区,就会被视作本地时间.

所以,不如使用timestamp来存放datetime对象.

collections

见名知意,内建的集合模块,封装了很多有用的集合类

主要有:namedtuple,deque,defaultdict, OrderedDict, Counter….

namedtuple:

假使我们构建一个元组:

1
q = (1,2)

并不能知道这个元组是干什么用的,在这种情况下,就到了namedtuple登场的时候了:

1
2
3
4
5
6
Point = namedtuple("Point", ['x', 'y'])
p = Point(1,2)
p.x
// 1
p.y
// 2

这样对象就得到了很好的管理,做个试验吧:

1
2
isinstance(p,Point)
isinstance(p,tuple)

deque:

双向队列,如同其他的语言,deque具有append(),pop(),还支持appendleft()popleft().

例如:

1
2
3
4
5
6
//导入
q = deque(['a','b','c'])
q.append("D")
q // ['a','b','c','D']
q.appendleft("0")
q // ['0','a','b','c','D']

defaultdict:

专用来处理访问dict不存在key的一种方法.

1
2
3
dd = default(lambda: 'N/A') //default
dd['Key1'] = "Key1"
dd."Key2" // N/A

defaultdict,也可这样使用:

1
ldict = collections.defaultdict(list)

这样生成的,ldict就会变成子元素都是list的一个defaultdict了.

而defaultdict又是dict的子类,所以这个对象会变得非常灵活.(感觉上有点像泛型,虽然他们有质的区别)

OrderDict

我们都知道,dict的排列顺序是随机的,Key是无序的.

为了能够在迭代时确认Key的顺序,我们便使用OrderDict

Counter

Counter是一个简单的计数器,但他的用法却可以很灵活

比如:

1
2
3
4
5
from collections import Counter
c= Counter()
for char in 'Hello,World':
c[char] += 1
print(c)

c的输出为Counter({'l':3, 'o':2, .....})

base64

先来简要介绍一下Base64编码的原理,Base64使用 a-z A-Z 0-9 + / 这64个字符来表示二进制数据(不计等号,等号是用来补空位的),由于,计算机内的编码方式是2进制,2^6=64,因此,便将6个比特映射到一个Base64可打印字符上,就可以进行转换了.

比如:man这个字符串,转为Base64编码的过程为:

文本 M A N
ASCII 77 97 110

ASCII转为二进制位:
01001101 01100001 01101110

6比特分组:
010011 010110 000101 101110

得到索引:
19 22 5 46

查表进行Base64编码:
T W F u

所以,Base64编码后的数据比原始数据略长,为原来的4/3.

到这里就出现问题了,如果我二进制数据的长度不是6的整数倍怎么办呢?

事实上,当原数据长度不是3的整数倍时, 如果最后剩下一个输入数据,在编码结果后加2个“=”;如果最后剩下两个输入数据,编码结果后加1个“=”;如果没有剩下任何数据,就什么都不加.

现在就可以来看一下Python对Base64的支持了.

1
2
3
4
5
6
7
import base64
encoded = base64.b64encode(b'Hello,World')//注意这里是二进制格式化字符串
print(encoded)
//b'SGVsbG8sV29ybGQ='
type(encoded)
//<class 'byte'>
//返回的也是二进制数据

hashlib

hashlib是python的摘要算法模块,提供常见的摘要算法如:SHA,MD5等等

简单的说,摘要算法就是通过一个函数,把任意长度的数据转换为一个长度固定的数据串

只要源数据有一丁点的改变,摘要(digest)就会有翻天覆地的变化.所以经常用来进行软件或信息的检验.

摘要函数是一个单向函数,计算f(data)很容易,但通过digest反推data却非常困难。

md5d的摘要示例:

1
2
3
4
5
6
import hashlib
md5 = hashlib.md5()
md5.update("Hello,World".encode("utf-8"))
md5.update("This is Python!".encode("utf-8"))
md5.hexdigest()
//'d6a6851cd4f390744645be4f5646b52a'

还可以使用更加安全的SHA算法,调用方法基本类似.

itertools

注意:当使用不当时.itertools极其容易无限迭代

因此做实验时建议考虑加上time.sleep()

拥有无限迭代的迭代器有:

count: 进行自增1的迭代

1
2
3
4
5
import itertools, time
naturals = itertools.count(1)
for n in naturals:
print(n)
time.sleep(2)

输出:1 2 3 4 5 6 7.....

cycle: 进行循环迭代

1
2
3
4
cycles = itertools.cycle("ABCD")
for str in cycles:
print(str)
time.sleep(2)

输出: A B C D A B C D A....

repeat: 进行重复迭代(准确的说,这也可以不叫做无限迭代)

1
2
3
repeats = itertools.repeat("A", 3)
for repeats in cycles:
print(repeats)

输出: A A A

一次迭代,迭代器就会失效!

为了结束无限循环,可以使用takewhile()来截断出一个有限的序列:

1
2
3
4
5
naturals = itertools.count(1)
ns = itertools.takewhile(lambda x: x <= 10, naturals)
//在这里其实也可以直接遍历ns,因为itertools模块返回的都是迭代器Iterator
list(ns)
//[1,2,3,4,5,6,7,8,9,10]

再说两个经常用的函数:chain()groupby()

例如:

1
itertools.chain

将两个迭代器进行拼接,也可以理解成是在拓展一个迭代器.

1
2
for n in itertools.chain("ABC", "XYZ"):
print(n)

输出: "A","B","C","X","Y","Z"

1
itertools.groupby()

有点像数据库查询的GROUPBY..将元素分组,可以这样接受数据:

1
2
3
4
5
6
for key,val in itertools.groupby("AaaBbbCcc", lambda x : x.upper()):
print(key, list(val))
///返回
A ["A","a","a"]
B ["B","b","b"]
C ["C","c","c"]

只要后面函数的返回值相同,那么元素就被认为是同组的,这个返回的值就是元素的组名.

pickle

pickle这个模块负责进行对象的持久化,或者叫序列化.

一个对象的生命周期是不可能比一个Pyhton程序还长的,所以,为了使得这个对象在下次程序启动是仍能使用,pickle便提供了这样的接口.

pickle的核心API就是dump/dumps/load/loads这四个.

这是一个持久化的例子:

1
2
3
4
5
6
7
8
9
10
import pickle

data = {
'a': [1, 2.0, 3],
'b': ("character string", b"byte string"),
'c': {None, True, False}
}

with open('data.pickle', 'wb') as f:
pickle.dump(data, f, pickle.HIGHEST_PROTOCOL)

将已序列化的对象复原:

1
2
3
4
import pickle

with open('data.pickle', 'rb') as f:
data = pickle.load(f)