文章目录
常用内置模块
一、datetime模块
datetime模块:处理日期和时间的标准库。
epoch time:1970 年 1 月 1 日 00:00:00 UTC+00:00 时区的时刻;
timestamp:当前时间相对于 epoch time 的秒数。
from datetime import datetime, timedelta, timezone
# tzinfo:时区属性
# 获取当前 datetime
now = datetime.now()
print(now)
print(type(now))
# 用指定日期和时间创建datetime
dt = datetime(2019,1,1,0,0)
print(dt)
# datetime 转换为 timestamp(浮点数,单位:秒)
# 若存在小数位,小数位表示毫秒数
dt = datetime(2019,1,1,8,8)
print(dt.timestamp())
## timestamp 转换为 datetime
# 时间转换是 timestamp 与本地时间做转换
t = 1546301280.0
print(datetime.fromtimestamp(t)) # 本地时间
## 转换到 UTC 标准时区的时间
print(datetime.utcfromtimestamp(t)) # UTC 时间
## str ==》datetime
cday = datetime.strptime('2019-1-1 18:28:30','%Y-%m-%d %H:%M:%S')
print(cday)
## datetime ==》str
now = datetime.now()
print(now.strftime('%a, %b %d %H:%M'))
## datetime 加减
now = datetime.now()
print(now)
print(now + timedelta(hours=10))
print(now - timedelta(days=1))
print(now + timedelta(days=2, hours=12))
## 强制设置时区:本地时间 ==》UTC 时间
# 本地时间:系统设定时区的时间
# UTC 时间:UTC+0:00 时区的时间
tz_utc_8 = timezone(timedelta(hours=10))
now = datetime.now()
print(now)
dt = now.replace(tzinfo=tz_utc_8) # 强制设置为 utc+8:00
print(dt)
## 时区转换
# 步骤:1.utcnow()获取当前utc时间;2.astimezone()转换到任意时区时间
utc_dt = datetime.utcnow().replace(tzinfo=timezone.utc)
print(utc_dt)
# astimezone()将转换时区为北京时间
bj_dt = utc_dt.astimezone(timezone(timedelta(hours=8)))
print(bj_dt)
# astimezone()将转换时区为东京时间
tokyo_dt = utc_dt.astimezone(timezone(timedelta(hours=9)))
print(tokyo_dt)
# astimezone()将 bj_dt 转换时区为东京时间
tokyo_dt2 = bj_dt.astimezone((timezone(timedelta(hours=9))))
print(tokyo_dt2)
import re
def to_timestamp(dt_str, tz_str):
dt = datetime.strptime(dt_str, "%Y-%m-%d %H:%M:%S")
pattern = re.compile(r"UTC(.+?):")
tzstr = pattern.match(tz_str).group(1)
tz = timezone(timedelta(hours=int(tzstr)))
dttz = dt.replace(tzinfo=tz)
return dttz.timestamp()
t1 = to_timestamp('2015-6-1 08:10:30', 'UTC+7:00')
assert t1 == 1433121030.0, t1
t2 = to_timestamp('2015-5-31 16:10:30', 'UTC-09:00')
assert t2 == 1433121030.0, t2
print('Pass')
结果输出
2018-12-25 09:39:32.382525
<class 'datetime.datetime'>
2019-01-01 00:00:00
1546301280.0
2019-01-01 08:08:00
2019-01-01 00:08:00
2019-01-01 18:28:30
Tue, Dec 25 09:39
2018-12-25 09:39:32.385442
2018-12-25 19:39:32.385442
2018-12-24 09:39:32.385442
2018-12-27 21:39:32.385442
2018-12-25 09:39:32.385442
2018-12-25 09:39:32.385442+10:00
2018-12-25 01:39:32.385513+00:00
2018-12-25 09:39:32.385513+08:00
2018-12-25 10:39:32.385513+09:00
2018-12-25 10:39:32.385513+09:00
Pass
二、collections模块
集合模块,提供集合类
1、namedtuple() 函数
tuple的子类,用于创建自定义的 tuple 对象,并规定 tuple 元素的个数,可用属性来引用 tuple 的某个元素。
from collections import namedtuple
# namedtuple('名称', [属性list])
## 定义 Point
Point = namedtuple('Point',['x', 'y'])
p = Point(1, 2)
print(p.x)
print(p.y)
## 定义 Circle
Circle = namedtuple('Circle', ['x','y','r'])
c = Circle(3,5,9)
print(c.x, c.y, c.r)
print(isinstance(p, Point))
print(isinstance(p, tuple))
结果输出
1
2
3 5 9
True
True
2、deque() 函数
可高效实现插入和删除操作的双向列表,适用于队列和栈。
除了实现 list 的 append()和 pop()外,还支持 appendleft() 和 popleft() ==》非常高效地往头部添加或删除元素。
from collections import deque
q = deque(['a', 'b', 'c'])
q.append('x')
q.appendleft('y')
print(q)
结果输出
deque(['y', 'a', 'b', 'c', 'x'])
3、defaultdict() 函数
defaultdict()函数:当 Key 不存在时,返回一个默认值。其余与dict一样。
注意:默认值是调用函数返回的,而函数在创建 defaultdict 对象时传入。
from collections import defaultdict
dd = defaultdict(lambda : 'N/A')
dd['key1'] = 'abc'
print(dd['key1'])
print(dd['key2'])
结果输出
abc
N/A
4、OrderedDict() 函数
OrderedDict 的 Key 会按照插入的顺序排列,不是 Key 本身排序。
from collections import OrderedDict
d = dict([('a',1),('c',3),('b',2)])
print(d)
od = OrderedDict([('a',1),('c',3),('b',2)])
print(od)
od1 = OrderedDict()
od1['z'] = 1
od1['y'] = 2
od1['x'] = 3
print(list(od1.keys()))
结果输出
{'a': 1, 'c': 3, 'b': 2}
OrderedDict([('a', 1), ('c', 3), ('b', 2)])
['z', 'y', 'x']
使用 OrderedDict 实现一个 FIFO(先进先出)的 dict,当容量超出限制时,先删除最早添加的 Key。
from collections import OrderedDict
class LastUpdatedOrderedDict(OrderedDict):
def __init__(self, capacity):
super(LastUpdatedOrderedDict, self).__init__()
self._capacity = capacity
def __setitem__(self, key, value):
containsKey = 1 if key in self else 0
if len(self) - containsKey >= self._capacity:
last = self.popitem(last=False)
print('remove: ',last)
if containsKey:
del self[key]
print('set:',(key, value))
else:
print('add:', (key, value))
OrderedDict.__setitem__(self, key, value)
5、Counter() 函数
作用:计数器
## 统计字符出现的个数
from collections import Counter
c = Counter()
for ch in 'programming':
c[ch] = c[ch] + 1
print(c)
结果输出
Counter({'r': 2, 'g': 2, 'm': 2, 'p': 1, 'o': 1, 'a': 1, 'i': 1, 'n': 1})
三、struct模块
作用:解决 bytes 和其他二进制数据类型的转换。
import struct
print(struct.pack('>I', 10240099))
# b'\x00\x9c@c'
# >IH 的说明,后面的 bytes 依次变为 I:4 字节无符号整数和
# H: 2 字节无符号整数。
print(struct.unpack('>IH', b'\xf0\xf0\xf0\xf0\x80\x80'))
参数:pack第一个参数是处理指令。
‘>I’表示:>表示字节顺序是 big-endian,也就是网络序, I 表示 4 字节无符号整数。后面的参数个数要和处理指令一致。
四、hashlib模块
提供常见的摘要算法(哈希算法、散列算法),eg:MD5、SHA1等。修改一小点,结果完全不同。单向函数。
通过一个函数将任意长度的数据转换为一个长度固定的数据串(通常用16进制的字符串表示)。
1、MD5
MD5 是最常见的摘要算法,速度很快,生成结果是固定的 128 bit 字节,通常用一个 32 位的 16 进制字符串表示。
import hashlib
md5 = hashlib.md5()
md5.update('how to use md5 in python hashlib?'.encode('utf-8'))
print(md5.hexdigest())
## 多次调用 update()
md5 = hashlib.md5()
md5.update('how to use md5 in '.encode('utf-8'))
md5.update('python hashlib?'.encode('utf-8'))
print(md5.hexdigest())
## 改动一个字母
md5.update('how to use md5 in python hashlid?'.encode('utf-8'))
print(md5.hexdigest())
## 结果输出
# d26a53750bc40b38b65a520292f69306
# d26a53750bc40b38b65a520292f69306
# 9ac2e3728468630f3d1aecc058e78dff
2、SHA1
结果是 160 bit 字节,通常用一个 40 位的 16 进制字符串表示。
sha1 = hashlib.sha1()
sha1.update('how to use md5 in '.encode('utf-8'))
sha1.update('python hashlib?'.encode('utf-8'))
print(sha1.hexdigest())
## 结果输出
# b752d34ce353e2916e943dc92501021c8f6bca8c
注意:可能出现两个不同的数据通过某个摘要算法得到相同的摘要,只是非常困难。
3、应用:密码存储与校验
摘要算法不是加密算法,不能用于加密(因为无法通过摘要反推明文),只能用于防篡改或者验证用户口令。
import hashlib
db = {
'michael': 'e10adc3949ba59abbe56e057f20f883e',
'bob': '878ef96e86145580c38c87f0410ad153',
'alice': '99b1c2188db85afee403b1536010c2c9'
}
def login(user, password):
ps_md5 = hashlib.md5()
ps_md5.update(password.encode('utf-8'))
if ps_md5.hexdigest() == db[user]:
return True
else:
return False
print(login('bob','abc999'))
更安全方法:通过对原始口令加一个复杂字符串来实现,俗称“加盐”
eg:添加固定字符串、将不变的用户名作为salt的一部分。
根据用户输入的登录名和口令模拟用户注册,计算更安全的 MD5
import hashlib, random
def get_md5(s):
return hashlib.md5(s.encode('utf-8')).hexdigest()
class User(object):
def __init__(self, username, password):
self.username = username
self.salt = ''.join([chr(random.randint(48, 122)) for i in range(20)])
self.password = get_md5(password + self.salt)
db = {
'michael': User('michael', '123456'),
'bob': User('bob', 'abc999'),
'alice': User('alice', 'alice2008')
}
def login(username, password):
user = db[username]
return user.password == get_md5(password + user.salt)
assert login('michael', '123456')
assert login('bob', 'abc999')
assert login('alice', 'alice2008')
assert not login('michael', '1234567')
assert not login('bob', '123456')
assert not login('alice', 'Alice2008')
print('ok')
## ok
五、itertools 模块
itertools 模块提供用于迭代对象的函数。返回值为 Iterator,需要用 for 循环迭代获取元素。
1、“无限”迭代器
- itertools.count(5):从5开始的自然数序列。
==》5,6,7,8,9,10,11,12,13… - itertools.cycle(‘ABC’):将一个序列无限重复下去。
==》‘A’,‘B’,‘C’,‘A’,‘B’,‘C’,‘A’,‘B’,‘C’… - itertools.repeat():将一个元素无限重复下去,第二个参数可以限定重复次数。
- 注意:无限序列只有在 for 迭代时才会无限迭代下去,但是通常通过 takewhile() 等函数根据条件判断来截取一个有限的序列。
import itertools
natuals = itertools.count(1)
ns = itertools.takewhile(lambda x: x <= 10, natuals)
print(list(ns))
结果输出
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
2、chain() 迭代器
可以将一组迭代对象串联起来,形成一个更大的迭代器
for c in itertools.chain('ABC', 'XYZ'):
print(c)
# 迭代效果: 'A' 'B' 'C' 'X' 'Y' 'Z'
3、groupby() 迭代器
将相邻的重复元素挑出来放在一起。
for key, group in itertools.groupby('AAAaaaaaBBBbcCCAAa'):
print(key, list(group))
print('---------------------------------------------')
## 忽略大小写
for key, group in itertools.groupby('AAAaaaaaBBBbcCCAAa', lambda c: c.upper()):
print(key, list(group))
结果输出
A ['A', 'A', 'A']
a ['a', 'a', 'a', 'a', 'a']
B ['B', 'B', 'B']
b ['b']
c ['c']
C ['C', 'C']
A ['A', 'A']
a ['a']
---------------------------------------------
A ['A', 'A', 'A', 'a', 'a', 'a', 'a', 'a']
B ['B', 'B', 'B', 'b']
C ['c', 'C', 'C']
A ['A', 'A', 'a']
六、XML
1、DOM vs. SAX
两种操作XML方法:DOM 和 SAX。
- DOM 会把整个 XML 读入内存,解析为树 ==》占用内存大,解析慢,优点是可以任意遍历树的节点。
- SAX 是流模式,边读边解析,占用内存小,解析快,缺点是我们需要自
己处理事件 - 正常情况下:优先考虑SAX(DOM太占内存)
2、SAX
关键函数:start_element 、end_element 和 char_data
from xml.parsers.expat import ParserCreate
class DefaultSaxHandler(object):
def start_element(self, name, attrs):
print('sax: start_element: %s, attrs: %s' % (name, str(attrs)))
def end_element(self, name):
print('sax: end_element: %s' % name)
def char_data(self, text):
print('sax: char_data: %s' % text)
xml = r'''<?xml version="1.0"?>
<ol>
<li><a herf="/python">Python</a></li>
<li><a herf="/ruby">Ruby</a></li>
</ol>
'''
handler = DefaultSaxHandler()
parser = ParserCreate()
parser.StartElementHandler = handler.start_element
parser.EndElementHandler = handler.end_element
parser.CharacterDataHandler = handler.char_data
parser.Parse(xml)
结果输出
sax: start_element: ol, attrs: {}
sax: char_data:
sax: char_data:
sax: start_element: li, attrs: {}
sax: start_element: a, attrs: {'herf': '/python'}
sax: char_data: Python
sax: end_element: a
sax: end_element: li
sax: char_data:
sax: char_data:
sax: start_element: li, attrs: {}
sax: start_element: a, attrs: {'herf': '/ruby'}
sax: char_data: Ruby
sax: end_element: a
sax: end_element: li
sax: char_data:
sax: end_element: ol
3、XML的生成
最简单的方法:拼接字符串
L = []
L.append(r'<?xml version="1.0"?>')
L.append(r'<root>')
七、HTMLParser
解析HTML(HTML是XML的子集,但HTML的语法没有XML那么严格)
from html.parser import HTMLParser
from html.entities import name2codepoint
class MyHTMLParser(HTMLParser):
def handle_starttag(self, tag, attrs):
print('<%s>' % tag)
def handle_endtag(self, tag):
print('</%s>' % tag)
def handle_startendtag(self, tag, attrs):
print('<%s/>' % tag)
def handle_data(self, data):
print(data)
def handle_comment(self, data):
print('<!--', data, '-->')
def handle_entityref(self, name):
print('&%s;' % name)
def handle_charref(self, name):
print('&#%s;' % name)
parser = MyHTMLParser()
parser.feed('''<html>
<head></head>
<body>
<!-- test html parser -->
<p>Some <a href=\"#\">html</a> HTML tutorial...<br>END</p>
</body></html>''')
- feed() 方法可以多次调用,可以分部分传入数据。
八、urllib
提供一系列用于操作 URL 的功能。
1、get()
urllib.request 模块可抓取 URL 内容:发送get请求到指定的页面,然后返回 HTTP 的响应。
from urllib import request
# url = 'https://api.douban.com/v2/book/2129650'
url = 'http://www.douban.com/'
req = request.Request(url = url)
# 添加 HTTP 头,可以伪装成浏览器
req.add_header('User-Agent','Mozilla/6.0 (iPhone; CPU iPhones OS 8_0 like Mac OS X) AppleWebKit/536.26 (KHTML, like Gecko) Version/8.0 Mobile/10A5376e Safari/8536.25')
with request.urlopen(req) as f:
data = f.read()
print('Status:', f.status, f.reason)
for k, v in f.getheaders():
print('%s: %s' % (k, v))
print('Data:', data.decode('utf-8'))
2、post()
以POST发送一个请求,只需把参数 data 以 bytes 形式传入。
from urllib import request, parse
print('Login to weibo.cn...')
email = input('Email:')
passwd = input('Password:')
login_data = parse.urlencode([
('username', email),
('password', passwd),
('entry', 'mweibo'),
('client_id',''),
('savestate', '1'),
('ec', ''),
('pagerefer','https://passport.weibo.cn/signin/welcome?entry=nweibo&r=http%3A%2F%2Fm.weibo.cn%2F')
])
url = 'https://passport.weibo.cn/sso/login'
req = request.Request(url)
req.add_header('Origin', 'https://passport.weibo.cn')
req.add_header('User-Agent','Mozilla/6.0 (iPhone; CPU iPhones OS 8_0 like Mac OS X) AppleWebKit/536.26 (KHTML, like Gecko) Version/8.0 Mobile/10A5376e Safari/8536.25')
req.add_header('Referer','https://passport.weibo.cn/signin/login?entry=mweibo&res=wel&wm=3349&r=http%3A%2F%2Fm.weibo.cn%2F')
with request.urlopen(req, data=login_data.encode('utf-8')) as f:
print('Status:', f.status, f.reason)
for k, v in f.getheaders():
print('%s: %s' % (k, v))
print('Data:', f.read().decode('utf-8'))
3、Handler
若需要通过一个 Proxy 来访问网站,则利用 ProxyHandler 来处理。
九、常用第三方模块
1、PIL(Python Imaging Library)——图像处理
2、virtualenv
为应用创建一套 Python 运行环境
十、图形界面
第三方库:Tk、wxWidgets、Qt、GTK