【Python】程式設計筆記11
文章目錄
- 常用內建模組
常用內建模組
一、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\[email protected]'
# >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傳送一個