Python内置了很多模块,这些模块往往很有用.
处理时间和日期–datetime
1.获取当前的时间–以datetime对象方式返回1
2
3
4
5
6from 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
3time = datetime(2018,4,10,13,21,0)
print(time)
//2018-04-10 13:21:00
3.时间戳
为了解决不同时区的时间不同的问题,时间戳成为了统一全球的时间表达方式,并且,这也成为了计算机保存时间的统一方式.
至于时间戳为什么能够达到统一,来看这个例子.1
2timestamp = 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.字符串与时间的计算和转换
转换的过程事实上是相似的,如同其他语言,都要使用格式化符号来表示年份,星期,月,日和具体的时间.
字符串转datetime1
2
3cday = 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
3current = now.strftime("%a, %b %d %H:%M")
print(current)
//Thu March 30 02:55
时间的加减
由于计算机是使用的时间戳来存储的时间,那么就可用+或-来进行运算.
但是,如果为了更好地迁移,可以使用这样的模块timedelta.
例如:1
2
3
4
5from 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
4zone = 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
6utc_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:
假使我们构建一个元组:1q = (1,2)
并不能知道这个元组是干什么用的,在这种情况下,就到了namedtuple登场的时候了:1
2
3
4
5
6Point = namedtuple("Point", ['x', 'y'])
p = Point(1,2)
p.x
// 1
p.y
// 2
这样对象就得到了很好的管理,做个试验吧:1
2isinstance(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
3dd = default(lambda: 'N/A') //default
dd['Key1'] = "Key1"
dd."Key2" // N/A
defaultdict,也可这样使用:1ldict = collections.defaultdict(list)
这样生成的,ldict就会变成子元素都是list的一个defaultdict了.
而defaultdict又是dict的子类,所以这个对象会变得非常灵活.(感觉上有点像泛型,虽然他们有质的区别)
OrderDict
我们都知道,dict的排列顺序是随机的,Key是无序的.
为了能够在迭代时确认Key的顺序,我们便使用OrderDict
Counter
Counter是一个简单的计数器,但他的用法却可以很灵活
比如:1
2
3
4
5from 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编码的过程为:文本MANASCII7797110
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
7import base64
encoded = base64.b64encode(b'Hello,World')//注意这里是二进制格式化字符串
print(encoded)
//b'SGVsbG8sV29ybGQ='
type(encoded)
//
//返回的也是二进制数据
hashlib
hashlib是python的摘要算法模块,提供常见的摘要算法如:SHA,MD5等等
简单的说,摘要算法就是通过一个函数,把任意长度的数据转换为一个长度固定的数据串
只要源数据有一丁点的改变,摘要(digest)就会有翻天覆地的变化.所以经常用来进行软件或信息的检验.
摘要函数是一个单向函数,计算f(data)很容易,但通过digest反推data却非常困难。
md5d的摘要示例:1
2
3
4
5
6import 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
5import 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
4cycles = itertools.cycle("ABCD")
for str in cycles:
print(str)
time.sleep(2)
输出: A B C D A B C D A....
repeat: 进行重复迭代(准确的说,这也可以不叫做无限迭代)1
2
3repeats = itertools.repeat("A", 3)
for repeats in cycles:
print(repeats)
输出: A A A
一次迭代,迭代器就会失效!
为了结束无限循环,可以使用takewhile()来截断出一个有限的序列:1
2
3
4
5naturals = 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()
例如:1itertools.chain
将两个迭代器进行拼接,也可以理解成是在拓展一个迭代器.1
2for n in itertools.chain("ABC", "XYZ"):
print(n)
输出: "A","B","C","X","Y","Z"1itertools.groupby()
有点像数据库查询的GROUPBY..将元素分组,可以这样接受数据:1
2
3
4
5
6for 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
10import 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
4import pickle
with open('data.pickle', 'rb') as f:
data = pickle.load(f)