Python学习(七)

学习网址:廖雪峰的Python教程

常用的内建模块

Python内置了许多有用的模块,无需额外安装和配置,可以直接使用.

datetime

它是Python处理如期和时间的标准库.

获取当前日期和时间:

1
2
3
4
5
6
7
>>> from datetime import datetime
>>> now = datetime.datetime()
>>> now = datetime.now()
>>> print(now)
2017-04-06 16:35:16.378296
>>> print(type(now))
<class 'datetime.datetime'>

解释:datetime是一个模块,导入的是这个模块中的datetime类,如果仅仅是

import datetime,需要使用全类名,datetime.datetime.

datetime.now()是当前的时间和日期,类型是datetime类型.

获取指定的时间和日期:

1
2
3
4
>>> from datetime import datetime
>>> zd = datetime(2017,4,1,9,50)
>>> print(zd)
2017-04-01 09:50:00

datetime转换为timestamp

首先,什么是timestamp?通常把1970年1月1日,00:00:00 UTC+00:00时区的时刻称为epoch time,记做0,把当前时间相对于epoch time的秒数,叫做timestamp.

直接调用timestamp()方法,就可以获取当前时间的timestamp:

1
2
3
4
5
6
7
8
9
>>> from datetime import datetime
>>> zd = datetime(2017,4,1,9,50)
>>> zd.timestamp()
1491011400.0
timestamp转为datetime:
>>> from datetime import datetime
>>> time = 1491011400.0
>>> print(datetime.fromtimestamp(time))
2017-04-01 09:50:00

timestamp是一个浮点数,没有时区的概念,datetime是有时区的,这里只是对时间进行转换.

2017-04-01 09:50:00 实际上相当于 2017-04-01 09:50:00 UTC+8:00

timestamp直接转换为UTC时区标准时间:

1
2
3
4
>>> from datetime import datetime
>>> time = 1491011400.0
>>> print(datetime.utcfromtimestamp(time))
2017-04-01 01:50:00

本地时区为东8区,比UTC时区差了8小时.

str转换为datetime

将字符串类型的日期和时间,转换为datetime,调用datetime.strptime()方法和一个日期时间的格式化字符串:

1
2
3
4
>>> from datetime import datetime
>>> da = datetime.strptime('2022-4-1 13:28:30','%Y-%m-%d %H:%M:%S')
>>> print(da)
2022-04-01 13:28:30

这个字符串规定了日期和时间的格式,参考Python文档

转化后的datetime是没有时区信息的.

datetime转化为str

将一个datetime对象转化为字符串,通过strftime()方法实现,和一个格式化日期和时间的字符串:

1
2
3
4
>>> from datetime import datetime
>>> da = datetime.strptime('2022-4-1 13:28:30','%Y-%m-%d %H:%M:%S')
>>> print(da.strftime('%a,%b %d %H:%M'))
Fri,Apr 01 13:28

时间的加减计算

datetime加减计算,就是把datetime往后或向前计算,得到新的datetime,加减可以直接用 + 和 - 运算符,需要导入timedelta.

1
2
3
4
5
6
7
8
9
10
>>> from datetime import datetime,timedelta
>>> now = datetime.now()
>>> now
datetime.datetime(2017, 4, 6, 18, 19, 44, 769642)
>>> now + timedelta(hours=10)
datetime.datetime(2017, 4, 7, 4, 19, 44, 769642)
>>> now - timedelta(days = 2)
datetime.datetime(2017, 4, 4, 18, 19, 44, 769642)
>>> now +timedelta(days=33,hours=12)
datetime.datetime(2017, 5, 10, 6, 19, 44, 769642)

timedetla()方法可以算出,前后几天的日期和时间.

本地时间转换为UTC时间

本地时间是指带有时区信息的时间,北京时间为UTC+8:00时区的时间,UTC时间是指UTC+0:00时区的时间.

datetime类型有tzinfo时区属性,默认为None,无法区分这个datetime是哪个时区的时间,可以强行设置一个时区.

1
2
3
4
5
6
7
8
9
>>> from datetime import datetime, timezone, timedelta
>>> tz = timezone(timedelta(hours=8))
>>> now = datetime.now()
>>> now
datetime.datetime(2017, 4, 6, 18, 42, 9, 954572)
>>> ndt = now.replace(tzinfo=tz)
>>> ndt
datetime.datetime(2017, 4, 6, 18, 42, 9, 954572, tzinfo=datetime.timezone(datetime.timedelta
(0, 28800)))

时区转化

通过utcnow()拿到当前的UTC时间,转转换为任意时区时间:

1
2
3
4
5
6
>>> utc_da = datetime.utcnow().replace(tzinfo=timezone.utc)
>>> print(utc_da)
2017-04-06 10:50:16.899424+00:00
>>> bd_da = utc_da.astimezone(timezone(timedelta(hours=8)))
>>> print(bd_da)
2017-04-06 18:50:16.899424+08:00

通过带有时区的datetime,调用astimezone()方法,可以转换到任意时区.

datetime表示的时间需要时区信息才能确定一个特定的时间,否则只能视为本地时间.

要存储datetime的话,最好是将datetime转换为timestamp来存储,timestamp的值与时区没有关系.

练习

假设你获取了用户输入的日期和时间如2015-1-21 9:01:30,以及一个时区信息如UTC+5:00,均是str,请编写一个函数将其转换为timestamp:

1
2
3
4
5
6
7
8
from datetime import datetime, timezone, timedelta
def to_timestamp(dt_str,tz_str):
i = datetime.strptime(dt_str,'%Y-%m-%d %H:%M:%S')
tz = tz_str[3:-3]
dt = i.replace(tzinfo=timezone(timedelta(hours=int(tz))))
return dt.timestamp()
print(to_timestamp('2015-6-1 08:10:30', 'UTC+7:00'))

collections

是Python内置的集合模块,提供了一些集合类.

namedtuple

它是一个函数,用来创建自定义的tuple对象,规定了tuple元素的个数,并且可以用属性而不是索引来引用tuple的某个元素.

1
2
3
4
5
6
7
8
9
>>> from collections import namedtuple
>>> Name = namedtuple('Name',['fn','ln'])
>>> me = Name('snow','lu')
>>> me
Name(fn='snow', ln='lu')
>>> me.fn 通过属性引用元素
'snow'
>>> me.ln 通过属性引用元素
'lu'

还可以验证创建的Name是不是tuple对象:

1
2
3
4
>>> isinstance(me,Name)
True
>>> isinstance(me,tuple)
True

deque

是为了高效实现插入和删除操作的双向列表,使用list存储数据时,由于list是线性存储,数据量大的时候,插入和删除的效率很低.

1
2
3
4
5
6
7
8
9
10
11
12
>>> from collections import deque
>>> q = deque(['a','b','c','d'])
>>> q.append('x')
>>> q
deque(['a', 'b', 'c', 'd', 'x'])
>>> q.appendleft('o')
>>> q
deque(['o', 'a', 'b', 'c', 'd', 'x'])
>>> q.popleft()
'o'
>>> q
deque(['a', 'b', 'c', 'd', 'x'])

deque还支持appendleft()popleft()方法,更方便的从开始位置插入和删除.

defaultdict

在使用defaultdict时候,如果key不存在,可以返回一个默认值,而使用dict时,如果key不存在,会报错KeyError.

1
2
3
4
5
6
7
8
9
10
>>> from collections import defaultdict
>>> d = defaultdict(lambda:'N/A')
>>> d['key'] = 'abc'
>>> d['key']
'abc'
>>> d['x'] = 'ssss'
>>> d['x']
'ssss'
>>> d['y']
'N/A'

defaultdict和dict的区别就是如果key不存在就返回默认值,其他的和dict一样.

OrderedDict

在使用dict时候,如果想要保持key的顺序,就可以使用OrderedDict.

1
2
3
4
5
6
7
8
9
10
>>> from collections import OrderedDict
>>> d = dict([('a',2),('b',1),('c',4)])
>>> d
{'c': 4, 'b': 1, 'a': 2}
>>> od = OrderedDict([('a',2),('b',1),('c',4)])
>>> od
OrderedDict([('a', 2), ('b', 1), ('c', 4)])
>>> oo = OrderedDict(d)
>>> oo
OrderedDict([('c', 4), ('b', 1), ('a', 2)])

需要注意的是,OrderedDict的key是按照插入的顺序排列,不是key本身的顺序.

OrderedDict可以实现先进先出的dict,当容量超出限制时,先删除最早插入的Key

Counter

它是一个简单的计数器,可以统计字符出现的个数:

1
2
3
4
5
6
7
>>> from collections import Counter
>>> cc = Counter()
>>> for ch in 'language':
... cc[ch] = cc[ch]+1
...
>>> cc
Counter({'g': 2, 'a': 2, 'n': 1, 'e': 1, 'l': 1, 'u': 1})

Counter是dict的一个子类

1
2
>>>isinstance(cc,dict)
True

base64

Base64是一种用64个字符来表示任意二进制数据的方法.

通常再用记事本打开exe,jpg,pdf等文件时,会看到一堆乱码,这是因为二进制文件中包含很多无法显示和打印的字符,如果要让记事本这样的文本处理软件能够处理二进制数据,就需要一个二进制到字符串的转换方法,Base64就是一种常见的二进制编码的方法

首先准备一个含有64个字符的数组

1
['A', 'B', 'C', ... 'a', 'b', 'c', ... '0', '1', ... '+', '/']

然后对二进制数据进行处理,没3个字节一组,一共是3*8=24bit(一个字节,8个bit),

化为4组,每组刚好是6个bit.

然后,得到4个数字作为索引,查表,获得相应的4个字符,就是编码后的字符串.

Base64会把3字节的二进制数据编码为4字节的文本数据,长度增加33%,好处是编码后的文本数据可以在邮件正文,网页等直接显示.

如果要编码的数据不是3的倍数,最后会有剩余,Base64会用\x00字节在末尾补足后,再在编码的末尾加上1个或2个=号,表示补了多少字节,解码时候,会自动去掉.

1
2
3
4
5
>>> import base64
>>> base64.b64encode(b'binary\x00string')
b'YmluYXJ5AHN0cmluZw=='
>>> base64.b64decode(b'YmluYXJ5AHN0cmluZw==')
b'binary\x00string'

标准的Base64编码后可能会出现字符 + 和 / ,在URL中不能直接作为参数.

urlsafe的base64编码可以把字符 + 和 / 分别变成 - 和 _

1
2
3
4
5
6
>>> base64.b64encode(b'i\xb7\x1d\xfb\xef\xff')
b'abcd++//'
>>> base64.urlsafe_b64encode(b'i\xb7\x1d\xfb\xef\xff')
b'abcd--'
>>> base64.urlsafe_b64decode('abcd--')
b'i\xb7\x1d\xfb\xef\xff'

Base64是一种通过查表的编码方法,不能用于加密,即使使用自定义的编码表也不行.

Base64适用于小段内的编码,如:数字证书签名,Cookie的内容.

由于 = 字符也可能出现在Base64编码中,但 = 在URL,Cookie里面会造成歧义,所以,很多Base64编码后会把 = 去掉.

因为Base64是把3个字节变为4个字节,Base64编码的长度是4的倍数,因此,需要加上 = 把Base64字符串的长度变为4的倍数,就可以正常解码了.


真诚地希望能帮到你!