1. 程式人生 > >【Python】程式設計筆記11

【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&nbsp;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傳送一個