前言
什么是模塊?
一個模塊就是一個包含了python定義和聲明的文件。模塊的本質就是一段在其他文件中的代碼。
re模塊
1.正則表達式
正則表達式不僅在python中,在整個編程中都占有舉足輕重的作用。不管你以后做不做開發,只要你是一個程序員就應該了解正則表達式的基本使用。如果未來要在爬蟲領域發展,更要學好這方面的知識。
re模塊本質上和正則表達式沒有任何的關系。他們的關系類似於time模塊和時間的關系。在沒有接觸python之前,不知道time模塊,但是我們都知道時間,時間有自己本身的格式和規則,time模塊只不過是python提供給我們用來操作時間的一個工具。同樣的,不管有沒有python,正則表達式都是存在的,他有自己的格式和規則,而re模塊只是python提供給我們使用正則表達式的工具而已。
正則表達式和python沒有任何的關系,它是匹配字符串內容的一種規則。
官方定義:正則表達式是對字符串操作的一種邏輯公式,就是用事先定義好的一些特定字符、及這些特定字符的組合,組成一個“規則字符串”,這個“規則字符串”用來表達對字符串的一種過濾邏輯。
正則表達式是用於操作字符串的,我們要想約束在同一個位置上字符出現的范圍,就需要使用正則表達式中的一個規則:字符組。字符組的定義就是在同一個位置可能出現的各種字符組成了一個字符組,在正則表達式中用[]表示,[字符組],字符分為很多類,比如數字、字母、標點等等。
我們可以借助工具來驗證:http://tool.chinaz.com/regex/
正則 | 匹配字符 | 匹配結果 | 說明 |
[0123456789] | 5 | True | 在一個字符組里枚舉合法的所有字符,字符組里的任意一個字符 |
[0123456789] | a | False | 由於字符組中沒有"a"字符,所以不能匹配 |
[0-9] | 6 | True | 可以用-表示范圍,[0-9]就和[0123456789]是一個意思 |
[a-z] | d | True | 同樣的如果要匹配所有的小寫字母,直接用[a-z]就可以表示 |
[A-Z] | Q | True | [A-Z]就表示所有的大寫字母 |
[0-9a-fA-F] | c | True | 可以匹配數字,大小寫形式的a~f,用來驗證十六進制字符 |
字符:
元字符 | 匹配內容 |
. | 匹配除換行符以外任意字符 |
\w | 匹配字母或數字或下划線 |
\s | 匹配任意的空白符 |
\d | 匹配數字 |
\W | 匹配非字母數字下划線 |
\S | 匹配非空白符 |
\D | 匹配非數字 |
\n | 匹配一個換行符 |
\t | 匹配一個制表符(tab鍵) |
\b | 匹配單詞的開始或結束 |
\B | 匹配不是單詞的開始或結束的位置 |
^ | 匹配字符串的開始 |
$ | 匹配字符串的結尾 |
a|b | 匹配字符a或字符b |
() | 匹配括號內的表達式,也表示一個組 |
[...] | 匹配字符組中的字符 |
[^...] | 匹配除了字符組中字符的所有字符 |
備注:元字符中a|b如果匹配的兩個字符是包含關系時,將較長的字符放在前面。比如:'abc'和'abcdef',匹配兩個字符串時,如果較短的放在前面,輸入較長的字符時,由於計算機執行的方式是由左往右,此時執行匹配的結果就是'abc',而不會繼續匹配后面的'def'。
^和$的使用非常重要。^必須在最前面,$必須在最后面,當^和$同時出現時,要匹配的內容就是^和$之間的固定內容。比如:使用^as$來匹配一個文件,那文件內容必須是as,不是asas,也不是a...s
量詞:
量詞 | 用法說明 |
* | 重復零次或更多次 |
+ | 重復一次或更多次 |
? | 重復零次或一次 |
{n} | 重復n次 |
{n,} | 重復n次或更多次 |
{n,m} | 重復n次到m次 |
貪婪匹配和惰性匹配:
貪婪匹配:在滿足匹配時,匹配盡可能長的字符串,默認情況下,采用貪婪匹配
正則 | 待匹配字符 | 匹配結果 |
海.* | 海風海洋海域 | 海風海洋海域 |
海.+ | 海風海洋海域 | 海風海洋海域 |
海.? | 海風海洋海域 | 海風 海洋 海域 |
海.{1,2} | 海風海洋海域 | 海風海 海域 |
正則 | 待匹配字符 | 匹配結果 |
海.*? | 海風海洋海域 | 海 海 海 |
海.+? | 海風海洋海域 | 海風 海洋 海域 |
海.?? | 海風海洋海域 | 海 海 海 |
海.{1,2}? | 海風海洋海域 | 海風 海洋 海域 |
注意:前面的*,+,?等都是貪婪匹配,也就是盡可能匹配,后面加?號使其變成惰性匹配
.*?的用法
. 是任意字符 * 是取 0 至 無限長度 ? 是非貪婪模式。 何在一起就是 取盡量少的任意字符,一般不會這么單獨寫,他大多用在: .*?x 就是取前面任意長度的字符,直到一個x出現
正則 | 待匹配的字符 | 匹配結果 | 說明 |
\d+ | 55 | 55 | 表示所有的整數 |
0\.\d+ | 0.45 | 0.45 | 表示所有的正小數 |
\d+\.?\d* | 3.0 | 3.0 | 表示所有的非負數 |
身份證號碼是一個長度為15或18個字符的字符串,如果是15位則全部由數字組成,首位不能為0;如果是18位,則前17位全部是數字,首位不能為0,末位可能是數字或x,下面我們嘗試用正則來表示:
1.使用元字符a|b表示:^([1-9]\d{16}[0-9x]|[1-9]\d{14})$
2.使用量詞?實現15或18位兩者間差的三位的有或無:^[1-9]\d{14}(\d{2}[0-9x])?$
2.re模塊下的使用方法
在python中對正則表達式進行操作就需要引用一個模塊:import re
我們使用模塊,只需要兩個參數: 自己寫的正則表達式 和 待匹配的字符
re模塊中常用的三種方法:
import re #re.findall的使用需要兩個參數:正則表達式和待匹配的字符串。返回值是一個列表,列表中包含‘所有’符合條件的項 # findall(pattern, string, flags=0) ret = re.findall('\d','a1b2c3') print(ret) #['1', '2', '3'] 返回所有滿足匹配條件的結果,放在列表里 ret = re.findall('[^和]','風和日麗和雨') print(ret) #['風', '日', '麗', '雨'] #re.search的使用也需要兩個參數:正則表達式和待匹配的字符串。返回的是第一個滿足條件的項 # 使用.group()方法就可以獲取到具體的值,需要注意的是,如果沒有匹配上,使用.group()會報錯 # 所以應該在使用group方法之前做判斷 # search(pattern, string, flags=0) ret = re.search('\d','a1b2c3') print(ret) #<_sre.SRE_Match object; span=(1, 2), match='1'> 返回一個匹配到了的信息 res = ret.group() #需要借助.group()來返回匹配結果 print(res) # 1 返回匹配到的第一項內容 ret = re.search('a','[a2a3a4]').group() print(ret) #a ret = re.search('[a-z]','12345') print(ret) #None 要匹配的內容不存在時,返回 None res = ret.group() print(res) #報錯 AttributeError: 'NoneType' object has no attribute 'group' # 匹配元素不存在時,匹配結果會報錯,所以當數據量很大,我們又不知道匹配的元素是否存在時,為了避免報錯,對代碼優化 ret = re.search('[a-z]','12345') print(ret) if ret: res = ret.group() print(res) #re.match()的使用方法跟search相似,不同的是match方法的正則自帶^效果 # match(pattern, string, flags=0) ret = re.match('a','abac') print(ret) #<_sre.SRE_Match object; span=(0, 1), match='a'> res = ret.group() # 借助group() print(res) #a ret = re.match('a','baba') print(ret) #None 匹配字符串的開始,找不到返回None
使用.group()和正則()時,可以給group傳參
import re ret = re.search('([a-z])(\d)','ab2748cdef14g239') print(ret.group()) # 直接獲取正則規則匹配到的項 print(ret.group(2)) # 如果給group傳遞參數,那么傳遞的參數能夠代表在正則表達式中組的次序 print(ret.group(1)) # 從而獲取到對應次序上的值
備注:.groups()方法的使用 ,返回一個元組 接收所有含有在()內的元素 ,沒有則返回一個空元組,有幾個,就接收幾個。
不常用的方法:
import re #split 分割 ret = re.split('[ab]','abcd') print(ret) #['', '', 'cd'] 先按'a'分割得到''和'bcd',在對''和'bcd'分別按'b'分割 #sub 替換 ret = re.sub('\d', 'H', 'eva3egon4yuan4', 1)#將數字替換成'H',參數1表示只替換1個 print(ret) #evaHegon4yuan4 #subn ret = re.subn('\d', 'H', 'eva3egon4yuan4')#將數字替換成'H',返回元組(替換的結果,替換了多少次) print(ret) #('evaHegonHyuanH', 3)
re模塊的進階用法
要匹配的數據量非常大時,將正則表達式通過compile轉化為正則表達式對象可以提高匹配的效率,節省大量的時間,同過finditer可以返回一個存放匹配結果的迭代器,取值時一個一個的取,可以極大的節省內存。
import re #compile() 返回一個正則表達式對象 當要匹配的數據非常大時,使用comlile 可以提高效率,節省時間 #compile(pattern, flags=0):"Compile a regular expression pattern, returning a pattern object." obj = re.compile('\d{3}') #將正則表達式編譯成為一個 正則表達式對象,規則要匹配的是3個數字 print(obj) #re.compile('\\d{3}') ret = obj.search('abc123eeee') #正則表達式對象調用search,參數為待匹配的字符串 print(ret.group()) #結果 : 123 #finditer 返回一個存放匹配結果的迭代器 當匹配的數據量很大時,使用finditer 可以節省大量的內存 ret = re.finditer('\d', 'ds3sy4784a') #finditer返回一個存放匹配結果的迭代器 print(ret) # <callable_iterator object at 0x10195f940> print(next(ret).group()) #查看第一個結果 3 print(next(ret).group()) #查看第二個結果 4 print([i.group() for i in ret]) #查看剩余的左右結果 ['7', '8', '4']
findall的優先級查詢:
import re #findall中正則 () 的使用 :出現()時仍然按照正則規則去匹配,只不過在顯示的時候,只顯示分組中的內容 ret = re.findall('[a-z]\d','asd2fg5jk6') print(ret) #['d2', 'g5', 'k6'] ret = re.findall('[a-z](\d)','asd2fg5jk6') print(ret) #['2', '5', '6'] 對數字加上()后在正則表達式中跟不加()的結果是一樣的,但在findall中兩者輸出結果不一樣 ret = re.findall('www.(baidu|hao123).com','www.baidu.com') print(ret) #['baidu'] 這是因為findall會優先把匹配結果組里內容返回,如果想要匹配結果,取消權限即可,在括號的最前面加:?: ret = re.findall('www.(?:baidu|hao123).com','www.baidu.com') print(ret) #['www.baidu.com'] 加上?:就會取消這個權限
split的優先級查詢:
ret=re.split("\d+","eva3egon4yuan") print(ret) #結果 : ['eva', 'egon', 'yuan'] ret=re.split("(\d+)","eva3egon4yuan") print(ret) #結果 : ['eva', '3', 'egon', '4', 'yuan'] #在匹配部分加上()之后所切出的結果是不同的, #沒有()的沒有保留所匹配的項,但是有()的卻能夠保留了匹配的項, #這個在某些需要保留匹配部分的使用過程是非常重要的。
標簽的匹配
import re ret = re.search('<\w+>\w+</\w+>','<html>hello</html>') print(ret.group()) #初步實現了匹配標簽,當前后<...>的內容不一樣時也能匹配,所以約束的不完全 #當我們想要實現前后的標簽內容一樣時,可以在分組中利用?P<name>的形式給分組起名字(?P(大寫的P) ret = re.search('<(?P<name>\w+)>\w+</(?P=name)>','<html>hello</html>') print(ret.group()) #此時就可以保證匹配的前后標簽一樣 print(ret.group('name')) #可以直接用group('名字')拿到對應的值 #另一種方法:(不推薦使用) ret = re.search(r"<(\w+)>\w+</\1>","<h1>hello</h1>") #如果不給組起名字,也可以用\序號來找到對應的組,表示要找的內容和前面的組內容一致 #獲取的匹配結果可以直接用group(序號)拿到對應的值 print(ret.group(1)) #也能實現匹配的前后標簽一樣 print(ret.group()) #結果 :<h1>hello</h1>
匹配整數
import re ret=re.findall(r"\d+","1-2*(60+(-40.35/5)-(-4*3))") print(ret) #['1', '2', '60', '40', '35', '5', '4', '3'] ret=re.findall(r"-?\d+\.\d*|(-?\d+)","1-2*(60+(-40.35/5)-(-4*3))") print(ret) #['1', '-2', '60', '', '5', '-4', '3'] ret.remove("") print(ret) #['1', '-2', '60', '5', '-4', '3']
數字匹配
1、 匹配一段文本中的每行的郵箱 http://blog.csdn.net/make164492212/article/details/51656638 2、 匹配一段文本中的每行的時間字符串,比如:‘1990-07-12’; 分別取出1年的12個月(^(0?[1-9]|1[0-2])$)、 一個月的31天:^((0?[1-9])|((1|2)[0-9])|30|31)$ 3、 匹配qq號。(騰訊QQ號從10000開始) [1,9][0,9]{4,} 4、 匹配一個浮點數。 ^(-?\d+)(\.\d+)?$ 或者 -?\d+\.?\d* 5、 匹配漢字。 ^[\u4e00-\u9fa5]{0,}$ 6、 匹配出所有整數
爬蟲的應用
從一個網站上匹配自己需要的信息,添加到一個新的文件中
import requests import re import json def getPage(url): response=requests.get(url) return response.text def parsePage(s): com=re.compile('<div class="item">.*?<div class="pic">.*?<em .*?>(?P<id>\d+).*?<span class="title">(?P<title>.*?)</span>' '.*?<span class="rating_num" .*?>(?P<rating_num>.*?)</span>.*?<span>(?P<comment_num>.*?)評價</span>',re.S) ret=com.finditer(s) for i in ret: yield { "id":i.group("id"), "title":i.group("title"), "rating_num":i.group("rating_num"), "comment_num":i.group("comment_num"), } def main(num): url='https://movie.douban.com/top250?start=%s&filter='%num response_html=getPage(url) ret=parsePage(response_html) print(ret) f=open("move_info7","a",encoding="utf8") for obj in ret: print(obj) data=json.dumps(obj,ensure_ascii=False) f.write(data+"\n") if __name__ == '__main__': count=0 for i in range(10): main(count) count+=25

import re import json from urllib.request import urlopen def getPage(url): response = urlopen(url) return response.read().decode('utf-8') def parsePage(s): com = re.compile( '<div class="item">.*?<div class="pic">.*?<em .*?>(?P<id>\d+).*?<span class="title">(?P<title>.*?)</span>' '.*?<span class="rating_num" .*?>(?P<rating_num>.*?)</span>.*?<span>(?P<comment_num>.*?)評價</span>', re.S) ret = com.finditer(s) for i in ret: yield { "id": i.group("id"), "title": i.group("title"), "rating_num": i.group("rating_num"), "comment_num": i.group("comment_num"), } def main(num): url = 'https://movie.douban.com/top250?start=%s&filter=' % num response_html = getPage(url) ret = parsePage(response_html) print(ret) f = open("move_info7", "a", encoding="utf8") for obj in ret: print(obj) data = str(obj) f.write(data + "\n") count = 0 for i in range(10): main(count) count += 25
flags的用法:
flags有很多可選值: re.I(IGNORECASE)忽略大小寫,括號內是完整的寫法 re.M(MULTILINE)多行模式,改變^和$的行為 re.S(DOTALL)點可以匹配任意字符,包括換行符 #這個比較常用 re.L(LOCALE)做本地化識別的匹配,表示特殊字符集 \w, \W, \b, \B, \s, \S 依賴於當前環境,不推薦使用 re.U(UNICODE) 使用\w \W \s \S \d \D使用取決於unicode定義的字符屬性。在python3中默認使用該flag re.X(VERBOSE)冗長模式,該模式下pattern字符串可以是多行的,忽略空白字符,並可以添加注釋
collections模塊(擴展數據類型)
在內置數據類型(dict、list、set、tuple)的基礎上,collections模塊還提供了幾個額外的數據類型:Counter、deque、defaultdict、namedtuple和OrderedDict等。
1.namedtuple: 生成可以使用名字來訪問元素內容的tuple
2.deque: 雙端隊列,可以快速的從另外一側追加和推出對象
3.Counter: 計數器,主要用來計數
4.OrderedDict: 有序字典
5.defaultdict: 帶有默認值的字典
1.namedtuple
我們知道tuple
可以表示不變集合,例如,一個點的二維坐標就可以表示成:
>>> p = (1, 2)
但是,看到(1, 2),很難看出這個tuple是用來表示一個坐標的。
這時,namedtuple
就派上了用場:
from collections import namedtuple point = namedtuple('Point',['x','y']) p1 = point(1,2) print(p1) #Point(x=1, y=2) #可以很明確的表示數據是什么 print(p1.x,p1.y) #1 2 #取數據的時候不會亂 不管在任何時候從元組中取數據 都可以明確的知道要取的內容
類似的,如果要用坐標和半徑表示一個圓,也可以用namedtuple
定義:
#namedtuple('名稱', [屬性list]): Circle = namedtuple('Circle', ['x', 'y', 'r'])
生活中我們也會使用namedtuple來描述一副撲克牌
from collections import namedtuple Card = namedtuple('Card',['colour','value']) Card1 = Card('紅桃','A') print(Card1) #Card(colour='紅桃', value='A')
2.deque
使用list存儲數據時,按索引訪問元素很快,但是插入和刪除元素就很慢了,因為list是線性存儲,數據量大的時候,插入和刪除效率很低。
deque是為了高效實現插入和刪除操作的雙向列表,適合用於隊列和棧:
deque是雙端隊列,就先講下隊列 queue
隊列遵循FIFO原則(FIFO =first in first out),也就是先進先出原則,所以火車票購票排隊可以采用這個原則,先排隊的先出票。
import queue q = queue.Queue() q.put(3) q.put(7) q.put(5) print(q) #<queue.Queue object at 0x00000216E7B1EE48> print(q.get()) #3 先進先出 print(q.get()) #7 print(q.get()) #5
from collections import deque dq = deque() print(dq) #deque([]) 默認一個列表 print(dq.append(4)) #None 無返回值 dq.append(6) dq.append(3) print(dq) #deque([4, 6, 3]) 依次添加 dq.appendleft(7) print(dq) #deque([7, 4, 6, 3]) 在最前面直接添加 print(dq.pop()) # 3 從最后面刪除 print(dq.popleft()) # 7 從最左邊刪除
deque除了實現list的append()
和pop()
外,還支持appendleft()
和popleft()
,這樣就可以非常高效地往頭部添加或刪除元素。
3.Counter
Counter類的目的是用來跟蹤值出現的次數。它是一個無序的容器類型,以字典的鍵值對形式存儲,其中元素作為key,其計數作為value。計數值可以是任意的Interger(包括0和負數)。Counter類和其他語言的bags或multisets很相似。
c = Counter('abcdeabcdabcaba') print(c) 輸出:Counter({'a': 5, 'b': 4, 'c': 3, 'd': 2, 'e': 1})
4.OrderedDict
使用dict時,Key是無序的。在對dict做迭代時,我們無法確定Key的順序。
如果要保持Key的順序,可以用OrderedDict
:
d = dict([('a', 1), ('b', 2), ('c', 3)]) print(d) #{'a': 1, 'b': 2, 'c': 3} from collections import OrderedDict od = OrderedDict({'a': 1, 'b': 2, 'c': 3}) print(od) #OrderedDict([('a', 1), ('b', 2), ('c', 3)]) od = OrderedDict([('a', 1), ('b', 2), ('c', 3)]) print(od) #OrderedDict([('a', 1), ('b', 2), ('c', 3)])
注意,OrderedDict
的Key會按照插入的順序排列,不是Key本身排序:
>>> od = OrderedDict() >>> od['z'] = 1 >>> od['y'] = 2 >>> od['x'] = 3 >>> od.keys() # 按照插入的Key的順序返回 ['z', 'y', 'x']
5.defaultdict
有如下值集合 [
11
,
22
,
33
,
44
,
55
,
66
,
77
,
88
,
99
,
90.
..],將所有大於
66
的值保存至字典的第一個key中,將小於
66
的值保存至第二個key的值中。
即: {
'k1'
: 大於
66
,
'k2'
: 小於
66
}

values = [11, 22, 33,44,55,66,77,88,99,90] my_dict = {} for value in values: if value>66: if my_dict.has_key('k1'): my_dict['k1'].append(value) else: my_dict['k1'] = [value] else: if my_dict.has_key('k2'): my_dict['k2'].append(value) else: my_dict['k2'] = [value]
現在,我們可以通過模塊完成它。
from collections import defaultdict values = [11, 22, 33,44,55,66,77,88,99,90] my_dict = defaultdict(list) for value in values: if value>66: my_dict['k1'].append(value) else: my_dict['k2'].append(value)
在使用defaultdict時,defaultdict(可callable的)括號中必須是可調用的,也就是callable(參數)=True的
from collections import defaultdict ret = defaultdict() print(ret) #defaultdict(None, {}) ret = defaultdict(str) print(ret) #defaultdict(<class 'str'>, {}) print(callable(str)) #True def func(): print(11) ret = defaultdict(func) print(ret) #defaultdict(<function func at 0x000001EC70C43598>, {}) print(callable(func)) #True
使用dict
時,如果引用的Key不存在,就會拋出KeyError
。如果希望key不存在時,返回一個默認值,就可以用defaultdict
:
>>> from collections import defaultdict >>> dd = defaultdict(lambda: 'N/A') >>> dd['key1'] = 'abc' >>> dd['key1'] # key1存在 'abc' >>> dd['key2'] # key2不存在,返回默認值 'N/A'
random模塊
>>> import random #隨機小數 >>> random.random() # 大於0且小於1之間的小數 0.7664338663654585 >>> random.uniform(1,3) #大於1小於3的小數 1.6270147180533838 #隨機整數 >>> random.randint(1,5) # 大於等於1且小於等於5之間的整數 >>> random.randrange(1,10,2) # 大於等於1且小於10之間的奇數 #隨機選擇一個返回 >>> random.choice([1,'23',[4,5]]) # #1或者23或者[4,5] #隨機選擇多個返回,返回的個數為函數的第二個參數 >>> random.sample([1,'23',[4,5]],2) # #列表元素任意2個組合 [[4, 5], '23'] #打亂列表順序 >>> item=[1,3,5,7,9] >>> random.shuffle(item) # 打亂次序 >>> item [5, 1, 3, 7, 9] >>> random.shuffle(item) >>> item [5, 9, 7, 1, 3]
我們可以利用random生成一個六位數包含數字和字母的隨機驗證碼
import random def code(): list = [] for i in range(6): num = random.randint(0,9) #隨機生成一個數字 alpha = chr(random.randint(65,90)) #利用chr()的用法隨機輸出一個大寫字母 alpha_letter = chr(random.randint(97,122)) #同樣的隨機輸出一個小寫字母 alpha_add = random.choice([alpha,alpha_letter]) #從大小寫字母中隨機輸出一個,可以保證結果的均衡 add = random.choice([alpha_add,num]) #從數字和字母中隨機輸出一個,可以保證概率的平衡 list.append(str(add)) #這里必須使用str將隨機的數字字符串化,因為join()的分割條件必須全部是字符串 ret = ''.join(list) return ret print(code())
時間模塊
和時間有關系的我們就要用到時間模塊。在使用模塊之前,應該首先導入這個模塊:import time
#常用方法 1.time.sleep(secs) (線程)推遲指定的時間運行。單位為秒。 2.time.time() 獲取當前時間戳
表示時間的三種方式
在Python中,通常有這三種方式來表示時間:時間戳、元組(struct_time)、格式化的時間字符串:
(1)時間戳(timestamp) :通常來說,時間戳表示的是從1970年1月1日00:00:00開始按秒計算的偏移量。我們運行“type(time.time())”,返回的是float類型。
(2)格式化的時間字符串(Format String): ‘1999-12-06’
python中時間日期格式化符號:
%y 兩位數的年份表示(00-99) %Y 四位數的年份表示(000-9999) %m 月份(01-12) %d 月內中的一天(0-31) %H 24小時制小時數(0-23) %I 12小時制小時數(01-12) %M 分鍾數(00=59) %S 秒(00-59) %a 本地簡化星期名稱 %A 本地完整星期名稱 %b 本地簡化的月份名稱 %B 本地完整的月份名稱 %c 本地相應的日期表示和時間表示 %j 年內的一天(001-366) %p 本地A.M.或P.M.的等價符 %U 一年中的星期數(00-53)星期天為星期的開始 %w 星期(0-6),星期天為星期的開始 %W 一年中的星期數(00-53)星期一為星期的開始 %x 本地相應的日期表示 %X 本地相應的時間表示 %Z 當前時區的名稱 %% %號本身
(3)元組(struct_time) :也稱結構化時間,struct_time元組共有9個元素共九個元素:(年,月,日,時,分,秒,周幾,一年中第幾天等)
索引(Index) | 屬性(Attribute) | 值(Values) |
---|---|---|
0 | tm_year(年) | 比如2011 |
1 | tm_mon(月) | 1 - 12 |
2 | tm_mday(日) | 1 - 31 |
3 | tm_hour(時) | 0 - 23 |
4 | tm_min(分) | 0 - 59 |
5 | tm_sec(秒) | 0 - 60 |
6 | tm_wday(weekday) | 0 - 6(0表示周一) |
7 | tm_yday(一年中的第幾天) | 1 - 366 |
8 | tm_isdst(是否是夏令時) | 默認為0 |
首先,我們先導入time模塊,來認識一下python中表示時間的幾種格式:
#導入時間模塊 >>>import time #時間戳 >>>time.time() 1500875844.800804 #時間字符串 >>>time.strftime("%Y-%m-%d %X") '2017-07-24 13:54:37' >>>time.strftime("%Y-%m-%d %H-%M-%S") '2017-07-24 13-55-04' #時間元組:localtime將一個時間戳轉換為當前時區的struct_time time.localtime() time.struct_time(tm_year=2017, tm_mon=7, tm_mday=24, tm_hour=13, tm_min=59, tm_sec=37, tm_wday=0, tm_yday=205, tm_isdst=0)
小結:時間戳是計算機能夠識別的時間;時間字符串是人能夠看懂的時間;元組則是用來操作時間的
幾種格式之間的轉換
#時間戳-->結構化時間 #time.gmtime(時間戳) #UTC時間,與英國倫敦當地時間一致 #time.localtime(時間戳) #當地時間。例如我們現在在北京執行這個方法:與UTC時間相差8小時,UTC時間+8小時 = 北京時間 >>>time.gmtime(1500000000) time.struct_time(tm_year=2017, tm_mon=7, tm_mday=14, tm_hour=2, tm_min=40, tm_sec=0, tm_wday=4, tm_yday=195, tm_isdst=0) >>>time.localtime(1500000000) time.struct_time(tm_year=2017, tm_mon=7, tm_mday=14, tm_hour=10, tm_min=40, tm_sec=0, tm_wday=4, tm_yday=195, tm_isdst=0) #結構化時間-->時間戳 #time.mktime(結構化時間) >>>time_tuple = time.localtime(1500000000) >>>time.mktime(time_tuple) 1500000000.0
#結構化時間-->字符串時間 #time.strftime("格式定義","結構化時間") 結構化時間參數若不傳,則現實當前時間 >>>time.strftime("%Y-%m-%d %X") '2017-07-24 14:55:36' >>>time.strftime("%Y-%m-%d",time.localtime(1500000000)) '2017-07-14' #字符串時間-->結構化時間 #time.strptime(時間字符串,字符串對應格式) >>>time.strptime("2017-03-16","%Y-%m-%d") time.struct_time(tm_year=2017, tm_mon=3, tm_mday=16, tm_hour=0, tm_min=0, tm_sec=0, tm_wday=3, tm_yday=75, tm_isdst=-1) >>>time.strptime("07/24/2017","%m/%d/%Y") time.struct_time(tm_year=2017, tm_mon=7, tm_mday=24, tm_hour=0, tm_min=0, tm_sec=0, tm_wday=0, tm_yday=205, tm_isdst=-1)
#結構化時間 --> %a %b %d %H:%M:%S %Y串 #time.asctime(結構化時間) 如果不傳參數,直接返回當前時間的格式化串 >>>time.asctime(time.localtime(1500000000)) 'Fri Jul 14 10:40:00 2017' >>>time.asctime() 'Mon Jul 24 15:18:33 2017' #時間戳 --> %a %d %d %H:%M:%S %Y串 #time.ctime(時間戳) 如果不傳參數,直接返回當前時間的格式化串 >>>time.ctime() 'Mon Jul 24 15:19:07 2017' >>>time.ctime(1500000000) 'Fri Jul 14 10:40:00 2017'
計算時間差:
import time true_time=time.mktime(time.strptime('2018-02-28 08:30:00','%Y-%m-%d %H:%M:%S')) time_now=time.mktime(time.strptime('2017-03-01 11:00:00','%Y-%m-%d %H:%M:%S')) dif_time=time_now-true_time struct_time=time.gmtime(dif_time) print('過去了%d年%d月%d天%d小時%d分鍾%d秒'%(struct_time.tm_year-1970,struct_time.tm_mon-1, struct_time.tm_mday-1,struct_time.tm_hour, struct_time.tm_min,struct_time.tm_sec))
os模塊
os模塊是與操作系統交互的一個接口
os.getcwd() 獲取當前工作目錄,即當前python腳本工作的目錄路徑 os.chdir("dirname") 改變當前腳本工作目錄;相當於shell下cd os.curdir 返回當前目錄: ('.') os.pardir 獲取當前目錄的父目錄字符串名:('..') os.makedirs('dirname1/dirname2') 可生成多層遞歸目錄 os.removedirs('dirname1') 若目錄為空,則刪除,並遞歸到上一級目錄,如若也為空,則刪除,依此類推 os.mkdir('dirname') 生成單級目錄;相當於shell中mkdir dirname os.rmdir('dirname') 刪除單級空目錄,若目錄不為空則無法刪除,報錯;相當於shell中rmdir dirname os.listdir('dirname') 列出指定目錄下的所有文件和子目錄,包括隱藏文件,並以列表方式打印 #這是個重點 os.remove() 刪除一個文件 os.rename("oldname","newname") 重命名文件/目錄 os.stat('path/filename') 獲取文件/目錄信息 os.sep 輸出操作系統特定的路徑分隔符,win下為"\\",Linux下為"/" os.linesep 輸出當前平台使用的行終止符,win下為"\t\n",Linux下為"\n" os.pathsep 輸出用於分割文件路徑的字符串 win下為;,Linux下為: os.name 輸出字符串指示當前使用平台。win->'nt'; Linux->'posix' os.system("bash command") 運行shell命令,直接顯示 os.popen("bash command).read() 運行shell命令,獲取執行結果 os.environ 獲取系統環境變量
os.urandom(n) 生成一個隨機n位的bytes類型的字節 os.walk('dir') 括號中跟目錄路徑,生成一個包含該目錄下文件的生成器generator
os.path os.path.abspath(path) 返回path規范化的絕對路徑
os.path.split(path) 將path分割成目錄和文件名二元組返回
os.path.dirname(path) 返回path的目錄。其實就是os.path.split(path)的第一個元素
os.path.basename(path) 返回path最后的文件名。如何path以/或\結尾,那么就會返回空值。即os.path.split(path)的第二個元素 os.path.exists(path) 如果path存在,返回True;如果path不存在,返回False os.path.isabs(path) 如果path是絕對路徑,返回True os.path.isfile(path) 如果path是一個存在的文件,返回True。否則返回False os.path.isdir(path) 如果path是一個存在的目錄,則返回True。否則返回False os.path.join(path1[, path2[, ...]]) 將多個路徑組合后返回,第一個絕對路徑之前的參數將被忽略 os.path.getatime(path) 返回path所指向的文件或者目錄的最后訪問時間 os.path.getmtime(path) 返回path所指向的文件或者目錄的最后修改時間 os.path.getsize(path) 返回path的大小
注意:os.stat('path/filename') 獲取文件/目錄信息 的結構說明
stat 結構: st_mode: inode 保護模式 st_ino: inode 節點號。 st_dev: inode 駐留的設備。 st_nlink: inode 的鏈接數。 st_uid: 所有者的用戶ID。 st_gid: 所有者的組ID。 st_size: 普通文件以字節為單位的大小;包含等待某些特殊文件的數據。 st_atime: 上次訪問的時間。 st_mtime: 最后一次修改的時間。 st_ctime: 由操作系統報告的"ctime"。在某些系統上(如Unix)是最新的元數據更改的時間,在其它系統上(如Windows)是創建時間(詳細信息參見平台的文檔)。
sys模塊
sys模塊是與python解釋器交互的一個接口
sys.argv 命令行參數List,第一個元素是程序本身路徑 sys.exit(n) 退出程序,正常退出時exit(0),錯誤退出sys.exit(1) sys.version 獲取Python解釋程序的版本信息 sys.path 返回模塊的搜索路徑,初始化時使用PYTHONPATH環境變量的值 sys.platform 返回操作系統平台名稱
異常處理和status
import sys try: sys.exit(1) except SystemExit as e: print(e)
序列化模塊
在計算機中,只有字符串能被寫進文件中,同樣的計算機的網路傳輸存儲都是bytes類型,bytes類型可以跟字符串轉化。所以一個數據要想傳輸儲存,都要轉化成字符串的形式來實現,而生活中一些字典列表類型的數據是無法直接存儲和傳輸的,這是我們就需要對它們轉化,就是序列化。
定義:序列化——將原本的字典、列表等內容轉換成一個字符串的過程就叫做序列化。

比如,我們在python代碼中計算的一個數據需要給另外一段程序使用,那我們怎么給?
現在我們能想到的方法就是存在文件里,然后另一個python程序再從文件里讀出來。
但是我們都知道,對於文件來說是沒有字典這個概念的,所以我們只能將數據轉換成字典放到文件中。
你一定會問,將字典轉換成一個字符串很簡單,就是str(dic)就可以辦到了,為什么我們還要學習序列化模塊呢?
沒錯序列化的過程就是從dic 變成str(dic)的過程。現在你可以通過str(dic),將一個名為dic的字典轉換成一個字符串,
但是你要怎么把一個字符串轉換成字典呢?
聰明的你肯定想到了eval(),如果我們將一個字符串類型的字典str_dic傳給eval,就會得到一個返回的字典類型了。
eval()函數十分強大,但是eval是做什么的?e官方demo解釋為:將字符串str當成有效的表達式來求值並返回計算結果。
BUT!強大的函數有代價。安全性是其最大的缺點。
想象一下,如果我們從文件中讀出的不是一個數據結構,而是一句"刪除文件"類似的破壞性語句,那么后果實在不堪設設想。 而使用eval就要擔這個風險。 所以,我們並不推薦用eval方法來進行反序列化操作(將str轉換成python中的數據結構)
序列化的目的

json
Json模塊提供了四個功能:dumps、dump、loads、load。
dumps(序列化)和loads(反序列化)、dump(序列化)和load(反序列化)兩兩搭配使用
json.dumps(obj) 括號中加要序列化的對象 json.dump(obj,f) 括號中跟序列化對象和一個文件句柄,所以dump和load用於文件的寫和讀,且load只能反序列化只包含一個數據結構的文件。
注意:使用json序列化數據后,原數據中的引號(不管是''還是"")都會轉化為""(雙引號)

import json dic = {'k1':'v1','k2':'v2','k3':'v3'} str_dic = json.dumps(dic) #序列化:將一個字典轉換成一個字符串 print(type(str_dic),str_dic) #<class 'str'> {"k3": "v3", "k1": "v1", "k2": "v2"} #注意,json轉換完的字符串類型的字典中的字符串是由""表示的 dic2 = json.loads(str_dic) #反序列化:將一個字符串格式的字典轉換成一個字典 #注意,要用json的loads功能處理的字符串類型的字典中的字符串必須由""表示 print(type(dic2),dic2) #<class 'dict'> {'k1': 'v1', 'k2': 'v2', 'k3': 'v3'} list_dic = [1,['a','b','c'],3,{'k1':'v1','k2':'v2'}] str_dic = json.dumps(list_dic) #也可以處理嵌套的數據類型 print(type(str_dic),str_dic) #<class 'str'> [1, ["a", "b", "c"], 3, {"k1": "v1", "k2": "v2"}] list_dic2 = json.loads(str_dic) print(type(list_dic2),list_dic2) #<class 'list'> [1, ['a', 'b', 'c'], 3, {'k1': 'v1', 'k2': 'v2'}]

import json f = open('json_file','w') dic = {'k1':'v1','k2':'v2','k3':'v3'} json.dump(dic,f) #dump方法接收一個文件句柄,直接將字典轉換成json字符串寫入文件 f.close() f = open('json_file') dic2 = json.load(f) #load方法接收一個文件句柄,直接將文件中的json字符串轉換成數據結構返回 f.close() print(type(dic2),dic2)

import json f = open('file','w') json.dump({'國籍':'中國'},f) ret = json.dumps({'國籍':'中國'}) f.write(ret+'\n') json.dump({'國籍':'美國'},f,ensure_ascii=False) ret = json.dumps({'國籍':'美國'},ensure_ascii=False) f.write(ret+'\n') f.close()

Serialize obj to a JSON formatted str.(字符串表示的json對象)
Skipkeys:默認值是False,如果dict的keys內的數據不是python的基本類型(str,unicode,int,long,float,bool,None),設置為False時,就會報TypeError的錯誤。此時設置成True,則會跳過這類key ensure_ascii:,當它為True的時候,所有非ASCII碼字符顯示為\uXXXX序列,只需在dump時將ensure_ascii設置為False即可,此時存入json的中文即可正常顯示。) If check_circular is false, then the circular reference check for container types will be skipped and a circular reference will result in an OverflowError (or worse). If allow_nan is false, then it will be a ValueError to serialize out of range float values (nan, inf, -inf) in strict compliance of the JSON specification, instead of using the JavaScript equivalents (NaN, Infinity, -Infinity). indent:應該是一個非負的整型,如果是0就是頂格分行顯示,如果為空就是一行最緊湊顯示,否則會換行且按照indent的數值顯示前面的空白分行顯示,這樣打印出來的json數據也叫pretty-printed json separators:分隔符,實際上是(item_separator, dict_separator)的一個元組,默認的就是(‘,’,’:’);這表示dictionary內keys之間用“,”隔開,而KEY和value之間用“:”隔開。 default(obj) is a function that should return a serializable version of obj or raise TypeError. The default simply raises TypeError. sort_keys:將數據根據keys的值進行排序。 To use a custom JSONEncoder subclass (e.g. one that overrides the .default() method to serialize additional types), specify it with the cls kwarg; otherwise JSONEncoder is used.

import json data = {'username':['李華','二愣子'],'sex':'male','age':16} json_dic2 = json.dumps(data,sort_keys=True,indent=2,separators=(',',':'),ensure_ascii=False) print(json_dic2)
當一個文件中包含多個數據結構時,我們可以通過for循環讀,每次讀一行,通過json.loads()逐行轉化
with open('logger',encoding='utf-8') as f1: for i in f1: print(json.loads(i))
備注:
json序列化時定制支持datetime類型,和到中文讓他保留中文形式
json序列化時,可以處理的數據類型有哪些?如何定制支持datetime類型
自定義時間序列化轉換器
import json from json import JSONEncoder from datetime import datetime class ComplexEncoder(JSONEncoder): def default(self, obj): if isinstance(obj, datetime): return obj.strftime('%Y-%m-%d %H:%M:%S') else: return super(ComplexEncoder,self).default(obj) d = { 'name':'alex','data':datetime.now()} print(json.dumps(d,cls=ComplexEncoder)) # {"name": "alex", "data": "2018-05-18 19:52:05"}
json序列化時遇到中文會默認轉換成unicode ,如何讓他保留中文形式
import json a=json.dumps({"ddf":"你好"},ensure_ascii=False) print(a) #{"ddf": "你好"}
pickle
json & pickle 模塊
用於序列化的兩個模塊
- json,用於字符串 和 python數據類型間進行轉換
- pickle,用於python特有的類型 和 python的數據類型間進行轉換
pickle模塊提供了四個功能:dumps、dump(序列化,存)、loads(反序列化,讀)、load (不僅可以序列化字典,列表...可以把python中任意的數據類型序列化)

import pickle dic = {'k1':'v1','k2':'v2','k3':'v3'} str_dic = pickle.dumps(dic) print(str_dic) #一串二進制內容 dic2 = pickle.loads(str_dic) print(dic2) #字典 import time struct_time = time.localtime(1000000000) print(struct_time) f = open('pickle_file','wb') pickle.dump(struct_time,f) f.close() f = open('pickle_file','rb') struct_time2 = pickle.load(f) print(struct_time2.tm_year)
這時候機智的你又要說了,既然pickle如此強大,為什么還要學json呢?
這里我們要說明一下,json是一種所有的語言都可以識別的數據結構。
如果我們將一個字典或者序列化成了一個json存在文件里,那么java代碼或者js代碼也可以拿來用。
但是如果我們用pickle進行序列化,其他語言就不能讀懂這是什么了~
所以,如果你序列化的內容是列表或者字典,我們非常推薦你使用json模塊
但如果出於某種原因你不得不序列化其他的數據類型,而未來你還會用python對這個數據進行反序列化的話,那么就可以使用pickle
shelve
shelve也是python提供給我們的序列化工具,比pickle用起來更簡單一些。
shelve只提供給我們一個open方法,是用key來訪問的,使用起來和字典類似。

import shelve f = shelve.open('shelve_file') f['key'] = {'int':10, 'float':9.5, 'string':'Sample data'} #直接對文件句柄操作,就可以存入數據 f.close() import shelve f1 = shelve.open('shelve_file') existing = f1['key'] #取出數據的時候也只需要直接用key獲取即可,但是如果key不存在會報錯 f1.close() print(existing)
這個模塊有個限制,它不支持多個應用同一時間往同一個DB進行寫操作。所以當我們知道我們的應用如果只進行讀操作,我們可以讓shelve通過只讀方式打開DB

import shelve f = shelve.open('shelve_file', flag='r') existing = f['key'] f.close() print(existing)
由於shelve在默認情況下是不會記錄待持久化對象的任何修改的,所以我們在shelve.open()時候需要修改默認參數,否則對象的修改不會保存。

import shelve f1 = shelve.open('shelve_file') print(f1['key']) f1['key']['new_value'] = 'this was not here before' f1.close() f2 = shelve.open('shelve_file', writeback=True) print(f2['key']) f2['key']['new_value'] = 'this was not here before' f2.close()
writeback方式有優點也有缺點。優點是減少了我們出錯的概率,並且讓對象的持久化對用戶更加的透明了;但這種方式並不是所有的情況下都需要,首先,使用writeback以后,shelf在open()的時候會增加額外的內存消耗,並且當DB在close()的時候會將緩存中的每一個對象都寫入到DB,這也會帶來額外的等待時間。因為shelve沒有辦法知道緩存中哪些對象修改了,哪些對象沒有修改,因此所有的對象都會被寫入。
hashlib模塊
算法介紹
Python的hashlib模塊中提供了常見的摘要算法,如MD5,SHA1等等。
什么是摘要算法呢?摘要算法又稱哈希算法、散列算法。它通過一個函數,把任意長度的數據轉換為一個長度固定的數據串(通常用16進制的字符串表示)。
摘要算法就是通過摘要函數f()對任意長度的數據data計算出固定長度的摘要digest,目的是為了發現原始數據是否被人篡改過。
摘要算法之所以能指出數據是否被篡改過,就是因為摘要函數是一個單向函數,計算f(data)很容易,但通過digest反推data卻非常困難。而且,對原始數據做一個bit的修改,都會導致計算出的摘要完全不同。
我們以常見的摘要算法MD5為例,計算出一個字符串的MD5值:
import hashlib md5 = hashlib.md5() md5.update('how to use md5 in python hashlib?') print md5.hexdigest() 計算結果如下: d26a53750bc40b38b65a520292f69306
如果數據量很大,可以分塊多次調用update(),最后計算的結果是一樣的:
md5 = hashlib.md5()
md5.update('how to use md5 in ') md5.update('python hashlib?') print md5.hexdigest()
MD5是最常見的摘要算法,速度很快,生成結果是固定的128 bit字節,通常用一個32位的16進制字符串表示。另一種常見的摘要算法是SHA1,調用SHA1和調用MD5完全類似:
import hashlib sha1 = hashlib.sha1() sha1.update('how to use sha1 in ') sha1.update('python hashlib?') print sha1.hexdigest()
SHA1的結果是160 bit字節,通常用一個40位的16進制字符串表示。比SHA1更安全的算法是SHA256和SHA512,不過越安全的算法越慢,而且摘要長度更長。
摘要算法應用
任何允許用戶登錄的網站都會存儲用戶登錄的用戶名和口令。如何存儲用戶名和口令呢?方法是存到數據庫表中:
name | password
--------+---------- michael | 123456 bob | abc999 alice | alice2008
如果以明文保存用戶口令,如果數據庫泄露,所有用戶的口令就落入黑客的手里。此外,網站運維人員是可以訪問數據庫的,也就是能獲取到所有用戶的口令。正確的保存口令的方式是不存儲用戶的明文口令,而是存儲用戶口令的摘要,比如MD5:
username | password
---------+--------------------------------- michael | e10adc3949ba59abbe56e057f20f883e bob | 878ef96e86145580c38c87f0410ad153 alice | 99b1c2188db85afee403b1536010c2c9
考慮這么個情況,很多用戶喜歡用123456,888888,password這些簡單的口令,於是,黑客可以事先計算出這些常用口令的MD5值,得到一個反推表:
'e10adc3949ba59abbe56e057f20f883e': '123456' '21218cca77804d2ba1922c33e0151105': '888888' '5f4dcc3b5aa765d61d8327deb882cf99': 'password'
這樣,無需破解,只需要對比數據庫的MD5,黑客就獲得了使用常用口令的用戶賬號。
對於用戶來講,當然不要使用過於簡單的口令。但是,我們能否在程序設計上對簡單口令加強保護呢?
由於常用口令的MD5值很容易被計算出來,所以,要確保存儲的用戶口令不是那些已經被計算出來的常用口令的MD5,這一方法通過對原始口令加一個復雜字符串來實現,俗稱“加鹽”:
hashlib.md5("salt".encode("utf8"))
經過Salt(鹽)處理的MD5口令,只要Salt不被黑客知道,即使用戶輸入簡單口令,也很難通過MD5反推明文口令。
但是如果有兩個用戶都使用了相同的簡單口令比如123456,在數據庫中,將存儲兩條相同的MD5值,這說明這兩個用戶的口令是一樣的。有沒有辦法讓使用相同口令的用戶存儲不同的MD5呢?
如果假定用戶無法修改登錄名,就可以通過把登錄名作為Salt的一部分來計算MD5,從而實現相同口令的用戶也存儲不同的MD5。
摘要算法在很多地方都有廣泛的應用。要注意摘要算法不是加密算法,不能用於加密(因為無法通過摘要反推明文),只能用於防篡改,但是它的單向計算特性決定了可以在不存儲明文口令的情況下驗證用戶口令。還可以應用於校驗文件的一致性,在網絡上傳和下載,保證多台機器狀態的一致。在這些地方我們可以用到摘要算法。
configparser模塊
配置文件無處不在,配置文件的格式有很多種,比較常用的有兩種:一種是在python中用一個python文件作為配置文件(.py),這種配置文件里面的所有值都不需要轉換或者處理,直接就可以當做變量調用,但是它只適用於python中,通用性差。另一種是采用普通的文本格式作為配置文件(.txt),這種配置文件是通用的,但是需要對文件處理,麻煩。當然還有其他的配置文件格式,比如:ini格式。configparser模塊適用於配置文件的格式與windows ini文件類似,可以包含一個或多個節/組(section,用[中括號+組名]表示),每個節可以有多個參數/項(option)(鍵=值)。
創建文件
來看一個好多軟件的常見文檔格式如下:
[DEFAULT]
ServerAliveInterval = 45 Compression = yes CompressionLevel = 9 ForwardX11 = yes [bitbucket.org] User = hg [topsecret.server.com] Port = 50022 ForwardX11 = no
如果想用python生成一個這樣的文檔怎么做呢?
import configparser config = configparser.ConfigParser() config["DEFAULT"] = {'ServerAliveInterval': '45', 'Compression': 'yes', 'CompressionLevel': '9', 'ForwardX11':'yes' } config['bitbucket.org'] = {'User':'hg'} config['topsecret.server.com'] = {'Host Port':'50022','ForwardX11':'no'} with open('example.ini', 'w') as configfile: config.write(configfile)
查找文件
import configparser config = configparser.ConfigParser() #---------------------------查找文件內容,基於字典的形式 print(config.sections()) # [] config.read('example.ini') print(config.sections()) # ['bitbucket.org', 'topsecret.server.com'] print('bytebong.com' in config) # False print('bitbucket.org' in config) # True print(config['bitbucket.org']["user"]) # hg print(config['DEFAULT']['Compression']) #yes print(config['topsecret.server.com']['ForwardX11']) #no print(config['bitbucket.org']) #<Section: bitbucket.org> for key in config['bitbucket.org']: # 注意,有default會默認default的鍵 print(key) print(config.options('bitbucket.org')) # 同for循環,找到'bitbucket.org'下所有鍵 print(config.items('bitbucket.org')) #找到'bitbucket.org'下所有鍵值對 print(config.get('bitbucket.org','compression')) # yes get方法Section下的key對應的value
增刪改操作
import configparser config = configparser.ConfigParser() config.read('example.ini') config.add_section('yuan') config.remove_section('bitbucket.org') config.remove_option('topsecret.server.com',"forwardx11") config.set('topsecret.server.com','k1','11111') config.set('yuan','k2','22222') config.write(open('new2.ini', "w"))
logging模塊
logging模塊是操作日志的模塊,使日志的格式更加規范,等級更加鮮明。日志的記錄有兩種手段:1.顯示在顯示屏上,更直觀。2.記錄在文件中,便於查看。
logging模塊有兩種用法:1.簡單的配置用法(要么顯示在屏幕上,要么寫在文件中,不能同時進行)。2.logger對象配置(兩者可以同時進行)
函數式簡單配置
import logging logging.debug('debug message') logging.info('info message') logging.warning('warning message') logging.error('error message') logging.critical('critical message')
默認情況下Python的logging模塊將日志打印到了標准輸出中,且只顯示了大於等於WARNING級別的日志,這說明默認的日志級別設置為WARNING(日志級別等級CRITICAL > ERROR > WARNING > INFO > DEBUG),默認的日志格式為日志級別:Logger名稱:用戶輸出消息。
靈活配置日志級別,日志格式,輸出位置:
import logging logging.basicConfig(level=logging.DEBUG, format='%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s', datefmt='%a, %d %b %Y %H:%M:%S', filename='/tmp/test.log', filemode='w') logging.debug('debug message') logging.info('info message') logging.warning('warning message') logging.error('error message') logging.critical('critical message')
配置參數:

logging.basicConfig()函數中可通過具體參數來更改logging模塊默認行為,可用參數有:
filename:用指定的文件名創建FiledHandler,這樣日志會被存儲在指定的文件中。
filemode:文件打開方式,在指定了filename時使用這個參數,默認值為“a”還可指定為“w”。
format:指定handler使用的日志顯示格式。
datefmt:指定日期時間格式。
level:設置rootlogger(后邊會講解具體概念)的日志級別
stream:用指定的stream創建StreamHandler。可以指定輸出到sys.stderr,sys.stdout或者文件(f=open(‘test.log’,’w’)),默認為sys.stderr。若同時列出了filename和stream兩個參數,則stream參數會被忽略。 format參數中可能用到的格式化串: %(name)s Logger的名字 %(levelno)s 數字形式的日志級別 %(levelname)s 文本形式的日志級別 %(pathname)s 調用日志輸出函數的模塊的完整路徑名,可能沒有 %(filename)s 調用日志輸出函數的模塊的文件名 %(module)s 調用日志輸出函數的模塊名 %(funcName)s 調用日志輸出函數的函數名 %(lineno)d 調用日志輸出函數的語句所在的代碼行 %(created)f 當前時間,用UNIX標准的表示時間的浮 點數表示 %(relativeCreated)d 輸出日志信息時的,自Logger創建以 來的毫秒數 %(asctime)s 字符串形式的當前時間。默認格式是 “2003-07-08 16:49:45,896”。逗號后面的是毫秒 %(thread)d 線程ID。可能沒有 %(threadName)s 線程名。可能沒有 %(process)d 進程ID。可能沒有 %(message)s用戶輸出的消息
logger對象配置
import logging logger = logging.getLogger() # 創建一個handler,用於寫入日志文件 fh = logging.FileHandler('test.log',encoding='utf-8')
# 再創建一個handler,用於輸出到控制台
ch = logging.StreamHandler()
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
fh.setLevel(logging.DEBUG)
fh.setFormatter(formatter)
ch.setFormatter(formatter)
logger.addHandler(fh) #logger對象可以添加多個fh和ch對象
logger.addHandler(ch)
logger.debug('logger debug message')
logger.info('logger info message')
logger.warning('logger warning message')
logger.error('logger error message')
logger.critical('logger critical message')
logging庫提供了多個組件:Logger、Handler、Filter、Formatter。Logger對象提供應用程序可直接使用的接口,Handler發送日志到適當的目的地,Filter提供了過濾日志信息的方法,Formatter指定日志顯示格式。另外,可以通過:logger.setLevel(logging.Debug)設置級別,當然,也可以通過fh.setLevel(logging.Debug)單對文件流設置某個級別。
shutil模塊
高級的 文件、文件夾、壓縮包 處理模塊
shutil.copyfileobj(fsrc, fdst[, length])
將文件內容拷貝到另一個文件中,可以部分內容
shutil.copyfile(src, dst)
拷貝文件
shutil.copymode(src, dst)
僅拷貝權限。內容、組、用戶均不變
shutil.copystat(src, dst)
拷貝狀態的信息,包括:mode bits, atime, mtime, flags
shutil.copy(src, dst)
拷貝文件和權限
shutil.copy2(src, dst)
拷貝文件和狀態信息
shutil.ignore_patterns(*patterns)
shutil.copytree(src, dst, symlinks=False, ignore=None)
遞歸的去拷貝文件
例如:copytree(source, destination, ignore=ignore_patterns('*.pyc', 'tmp*'))
shutil.rmtree(path[, ignore_errors[, onerror]])
遞歸的去刪除文件
shutil.move(src, dst)
遞歸的去移動文件
shutil.make_archive(base_name, format,...)
創建壓縮包並返回文件路徑,例如:zip、tar
- base_name: 壓縮包的文件名,也可以是壓縮包的路徑。只是文件名時,則保存至當前目錄,否則保存至指定路徑,
如:www =>保存至當前路徑
如:/Users/wupeiqi/www =>保存至/Users/wupeiqi/ - format: 壓縮包種類,“zip”, “tar”, “bztar”,“gztar”
- root_dir: 要壓縮的文件夾路徑(默認當前目錄)
- owner: 用戶,默認當前用戶
- group: 組,默認當前組
- logger: 用於記錄日志,通常是logging.Logger對象
shutil 對壓縮包的處理是調用 ZipFile 和 TarFile 兩個模塊來進行的