python幾個模塊的介紹

1.模塊的介紹

定義:html

Python 模塊(Module),是一個 Python 文件,以 .py 結尾,包含了 Python 對象定義和Python語句。node

模塊讓你可以有邏輯地組織你的 Python 代碼段。python

把相關的代碼分配到一個模塊裏能讓你的代碼更好用,更易懂。程序員

模塊能定義函數,類和變量,模塊裏也能包含可執行的代碼。web

 

2.time模塊

一、經常使用方法:正則表達式

1.time.sleep(secs) (線程)推遲指定的時間運行,單位爲秒。算法

2.time.time() 獲取當前時間戳。shell

二、在計算中時間共有三種方式:數據庫

1.時間戳: 一般來講,時間戳表示的是從1970年1月1日00:00:00開始按秒計算的偏移量。咱們運行「type(time.time())」,返回的是float類型(計算機可以識別的時間)。編程

2.格式化字符串時間: 格式化的時間字符串(Format String): ‘1999-12-06’ (人可以看懂的時間)。

3.結構化時間:元組(struct_time) struct_time元組共有9個元素共九個元素:(年,月,日,時,分,秒,一年中第幾周,一年中第幾天等(用來操做時間的)。

--------------------------咱們先以當前時間爲準--------------------------

#導入時間模塊
>>>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)

print(time.localtime()) #本地時區的struct_time
print(time.gmtime())    #UTC時區的struct_time
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 當前時區的名稱
%% %號自己
python中時間日期格式化符號

 

三、時間格式轉換:

 

#時間戳-->結構化時間
#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 %b %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('2017-09-11 08:30:00','%Y-%m-%d %H:%M:%S'))
time_now=time.mktime(time.strptime('2017-09-12 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))
View Code

 

 

3.datetime模塊

1.獲取當前日期和時間

from datetime import datetime

print(datetime.now())

'''
結果:2018-12-04 21:07:48.734886
'''

##注意:datetime是模塊,datetime模塊還包含一個datetime的類,經過from datetime import datetime導入的纔是datetime這個類。

若是僅導入import datetime,則必須引用全名datetime.datetime。

datetime.now()返回當前日期和時間,其類型是datetime。##
View Code

2.獲取指定日期和時間。(要指定某個日期和時間,咱們直接用參數構造一個datetime

from datetime import datetime

dt = datetime(2018,5,20,13,14)
print(dt)

'''
結果:2018-05-20 13:14:00
'''
View Code

3.datetime轉換爲timestamp(時間戳)

from datetime import datetime

dt = datetime.now()
new_timestamp = dt.timestamp()
print(new_timestamp)

'''
結果:1543931750.415896
'''
View Code

4.timestamp轉換爲datetime

import time
from datetime import datetime

new_timestamp = time.time()
print(datetime.fromtimestamp(new_timestamp))
View Code

5.str轉換爲datetime

不少時候,用戶輸入的日期和時間是字符串,要處理日期和時間,首先必須把str轉換爲datetime。轉換方法是經過datetime.strptime()實現,須要一個日期和時間的格式化字符串:

from datetime import datetime

t = datetime.strptime('2018-4-1 00:00','%Y-%m-%d %H:%M')
print(t)
'''
結果: 2018-04-01 00:00:00
'''
View Code

6.datetime轉換爲str

若是已經有了datetime對象,要把它格式化爲字符串顯示給用戶,就須要轉換爲str,轉換方法是經過strftime()實現的,一樣須要一個日期和時間的格式化字符串:

from datetime import datetime
now = datetime.now()
print(now.strftime('%a, %b %d %H:%M'))
Mon, May 05 16:28
View Code

7.datetime加減(對日期和時間進行加減實際上就是把datetime日後或往前計算,獲得新的datetime。加減能夠直接用+-運算符,不過須要導入timedelta這個類:)

from datetime import datetime, timedelta
now = datetime.now()
now
datetime.datetime(2015, 5, 18, 16, 57, 3, 540997)
now + timedelta(hours=10)
datetime.datetime(2015, 5, 19, 2, 57, 3, 540997)
now - timedelta(days=1)
datetime.datetime(2015, 5, 17, 16, 57, 3, 540997)
now + timedelta(days=2, hours=12)
datetime.datetime(2015, 5, 21, 4, 57, 3, 540997)
View Code

8.小結: 

datetime表示的時間須要時區信息才能肯定一個特定的時間,不然只能視爲本地時間。

若是要存儲datetime,最佳方法是將其轉換爲timestamp再存儲,由於timestamp的值與時區徹底無關。

 

4.random模塊

 1.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 v_code():
​
    code = ''
    for i in range(5):
​
        num=random.randint(0,9)
        alf=chr(random.randint(65,90))
        add=random.choice([num,alf])
        code="".join([code,str(add)])
​
    return code
​
print(v_code())
生成隨機驗證碼

 

 

5.os模塊 

一、介紹:os模塊是與操做系統交互的一個接口。(http://www.runoob.com/python/os-file-methods.html

當前執行這個python文件的工做目錄相關的工做路徑
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  獲取系統環境變量
​
#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模塊方法

二、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)是建立時間(詳細信息參見平臺的文檔)。
View Code

三、os路徑處理

#方式一:推薦使用
import os
#具體應用
import os,sys
possible_topdir = os.path.normpath(os.path.join(
    os.path.abspath(__file__),
    os.pardir, #上一級
    os.pardir,
    os.pardir
))
sys.path.insert(0,possible_topdir)


#方式二:不推薦使用
os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
View Code
在Linux和Mac平臺上,該函數會原樣返回path,在windows平臺上會將路徑中全部字符轉換爲小寫,並將全部斜槓轉換爲飯斜槓。
>>> os.path.normcase('c:/windows\\system32\\')   
'c:\\windows\\system32\\'   
   

規範化路徑,如..和/
>>> os.path.normpath('c://windows\\System32\\../Temp/')   
'c:\\windows\\Temp'   

>>> a='/Users/jieli/test1/\\\a1/\\\\aa.py/../..'
>>> print(os.path.normpath(a))
/Users/jieli/test1
View Code

 

6.sys模塊

 

 一、介紹:sys模塊是與python解釋器交互的一個接口

1 sys.argv           實現從程序外部向程序傳遞參數。(在命令行裏面輸打開路徑執行)

name=sys.argv[1] #命令行參數List,第一個元素是程序的自己路徑
  password = sys.argv[2]
  if name=='egon' and password == '123':
     print('繼續執行程序')
 else:
     exit()

2 sys.exit(n)        退出程序,正常退出時exit(0)
3 sys.version        獲取Python解釋程序的版本信息
4 sys.maxint         最大的Int值 ,最大能表示的數,與系統多少位有關
5 sys.path           返回模塊的搜索路徑,初始化時使用PYTHONPATH環境變量的值
6 sys.platform       返回操做系統平臺名稱

#=========知識儲備==========
#進度條的效果
[#             ]
[##            ]
[###           ]
[####          ]
#指定寬度
print('[%-15s]' %'#')
print('[%-15s]' %'##')
print('[%-15s]' %'###')
print('[%-15s]' %'####')
​
#打印%
print('%s%%' %(100)) #第二個%號表明取消第一個%的特殊意義
#可傳參來控制寬度
print('[%%-%ds]' %50) #[%-50s]
print(('[%%-%ds]' %50) %'#')
print(('[%%-%ds]' %50) %'##')
print(('[%%-%ds]' %50) %'###')
​
​
#=========實現打印進度條函數==========
import sys
import time
​
def progress(percent,width=50):
    if percent >= 1:
        percent=1
    show_str = ('%%-%ds' % width) % (int(width*percent)*'|')
    print('\r%s %d%%' %(show_str, int(100*percent)), end='')
​
​
#=========應用==========
data_size=1025
recv_size=0
while recv_size < data_size:
    time.sleep(0.1) #模擬數據的傳輸延遲
    recv_size+=1024 #每次收1024
​
    percent=recv_size/data_size #接收的比例
    progress(percent,width=70) #進度條的寬度70
打印進度條

  

7.shutil模塊

一、介紹:shutil模塊是對高級的文件、文件夾、壓縮包 處理的模塊。

1.shutil.copyfileobj(fsrc, fdst[, length]) 將文件內容拷貝到另外一個文件中

import shutil  
shutil.copyfileobj(open('old.xml','r'), open('new.xml', 'w'))

2.shutil.copyfile(src, dst) 拷貝文件

shutil.copyfile('f1.log', 'f2.log') #目標文件無需存在

3.shutil.copymode(src, dst) 僅拷貝權限。內容、組、用戶均不變

shutil.copymode('f1.log', 'f2.log') #目標文件必須存在

4.shutil.copystat(src, dst) 僅拷貝狀態的信息,包括:mode bits, atime, mtime, flags

shutil.copystat('f1.log', 'f2.log') #目標文件必須存在

5.shutil.copy(src, dst) 拷貝文件和權限

import shutil
shutil.copy('f1.log', 'f2.log')
shutil.copy2(src, dst)

6.拷貝文件和狀態信息

import shutil
shutil.copy2('f1.log', 'f2.log')
shutil.ignore_patterns(*patterns)
shutil.copytree(src, dst, symlinks=False, ignore=None)

7.遞歸的去拷貝文件夾

import shutil
shutil.copytree('folder1', 'folder2', ignore=shutil.ignore_patterns('*.pyc', 'tmp*')) #目標目錄不能存在,注意對folder2目錄父級目錄要有可寫權限,ignore的意思是排除

8.拷貝軟鏈接

import shutil
shutil.copytree('f1', 'f2', symlinks=True, ignore=shutil.ignore_patterns('*.pyc', 'tmp*'))
​
'''
一般的拷貝都把軟鏈接拷貝成硬連接,即對待軟鏈接來講,建立新的文件
'''

9.shutil.rmtree(path[, ignore_errors[, onerror]]) 遞歸的去刪除文件

import shutil
shutil.rmtree('folder1')
shutil.move(src, dst)

10. 遞歸的去移動文件,它相似mv命令,其實就是重命名。

import shutil
shutil.move('folder1', 'folder3')
shutil.make_archive(base_name, format,...)

11.建立壓縮包並返回文件路徑,例如:zip、tar

base_name: 壓縮包的文件名,也能夠是壓縮包的路徑。只是文件名時,則保存至當前目錄,不然保存至指定路徑,
如 data_bak                       =>保存至當前路徑
如:/tmp/data_bak =>保存至/tmp/
format: 壓縮包種類,「zip」, 「tar」, 「bztar」,「gztar」
root_dir:   要壓縮的文件夾路徑(默認當前目錄)
owner:  用戶,默認當前用戶
group:  組,默認當前組
logger: 用於記錄日誌,一般是logging.Logger對象
​
#將 /data 下的文件打包放置當前程序目錄
import shutil
ret = shutil.make_archive("data_bak", 'gztar', root_dir='/data')
   
   
#將 /data下的文件打包放置 /tmp/目錄
import shutil
ret = shutil.make_archive("/tmp/data_bak", 'gztar', root_dir='/data')
View Code

12.shutil 對壓縮包的處理是調用 ZipFile 和 TarFile 兩個模塊來進行的,詳細: zipfile壓縮解壓縮

import zipfile
 
# 壓縮
z = zipfile.ZipFile('laxi.zip', 'w')
z.write('a.log')
z.write('data.data')
z.close()
 
# 解壓
z = zipfile.ZipFile('laxi.zip', 'r')
z.extractall(path='.')
z.close()
View Code

13.tarfile壓縮解壓縮

import tarfile
​
# 壓縮
>>> t=tarfile.open('/tmp/egon.tar','w')
>>> t.add('/test1/a.py',arcname='a.bak')
>>> t.add('/test1/b.py',arcname='b.bak')
>>> t.close()
​
​
# 解壓
>>> t=tarfile.open('/tmp/egon.tar','r')
>>> t.extractall('/egon')
>>> t.close()
View Code

1四、shutil.make_archive(base_name, format,...)

建立壓縮包並返回文件路徑,例如:zip、tar

建立壓縮包並返回文件路徑,例如:zip、tar

    • base_name: 壓縮包的文件名,也能夠是壓縮包的路徑。只是文件名時,則保存至當前目錄,不然保存至指定路徑,
      如 data_bak                       =>保存至當前路徑
      如:/tmp/data_bak =>保存至/tmp/
    • format: 壓縮包種類,「zip」, 「tar」, 「bztar」,「gztar」
    • root_dir: 要壓縮的文件夾路徑(默認當前目錄)
    • owner: 用戶,默認當前用戶
    • group: 組,默認當前組
    • logger: 用於記錄日誌,一般是logging.Logger對象
#將 /data 下的文件打包放置當前程序目錄
import shutil
ret = shutil.make_archive("data_bak", 'gztar', root_dir='/data')
  
  
#將 /data下的文件打包放置 /tmp/目錄
import shutil
ret = shutil.make_archive("/tmp/data_bak", 'gztar', root_dir='/data')

 

 

8.序列化

一、定義:將本來的字典、列表等內容轉換成一個字符串的過程就叫作序列化。咱們把對象(變量)從內存中變成可存儲或傳輸的過程稱之爲序列化,在Python中叫pickling,在其餘語言中也被稱之爲serialization,marshalling,flattening等等,都是一個意思。

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

二、序列化的目的

一、以某種存儲形式使自定義對象持久化;
二、將對象從一個地方傳遞到另外一個地方。
三、使程序更具維護性。

 

 

9. json模塊

1介紹若是咱們要在不一樣的編程語言之間傳遞對象,就必須把對象序列化爲標準格式,好比XML,但更好的方法是序列化爲JSON,由於JSON表示出來就是一個字符串,能夠被全部語言讀取,也能夠方便地存儲到磁盤或者經過網絡傳輸。JSON不只是標準格式,而且比XML更快,並且能夠直接在Web頁面中讀取,很是方便。經過Python的json模塊,能夠將字符串形式的json數據轉化爲字典,也能夠將Python中的字典數據轉化爲字符串形式的json數據。

python序列化爲json時的數據類型轉換關係與json反序列化爲python數據類型對照關係

                

 

二、Json模塊提供的四個功能:dumps、dump、loads、load

json.dumps(): 將字典序列化爲json字符串

json.loads(): 將json字符串反序列化爲字典

json.dump(): 將字典序列化到一個文件,是文本文件,就是至關於將序列化後的json字符串寫入到一個文件

json.load(): 從文件中反序列出字典

總結: 不帶s的是序列到文件或者從文件中反序列化,帶s的是都在內存中操做不涉及到持久化
json的四個功能

dumps 及 loads

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'}]
dumps 及 loads

dump 及 load

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) 
dump 及 load

 

三、json字符串轉爲字典(json.load / json.loads)

兩個方法功能相似,可選參數也相同,最大的區別在於,json.load方法接受的輸入,即第一個參數,是包含json數據的文件對象,如open方法的返回對象,

json.loads接受的輸入是json字符串,而非文件對象。從輸入類型的區別也能夠看出二者的使用場合。

字典轉換爲json(json.dump / json.dumps)

對應於load和loads,dump的第一個參數是對象字典,第二個參數是文件對象,能夠直接將轉換後的json數據寫入文件,dumps的第一個參數是對象字典,其他都是可選參數。dump和dumps的可選參數相同,這些參數都至關實用,現將用到的參數記錄以下:

ensure_ascii 默認爲True,保證轉換後的json字符串中所有是ascii字符,非ascii字符都會被轉義。若是數據中存在中文或其餘非ascii字符,最好將ensure_ascii設置爲False,保證輸出結果正常。

indent 縮進,默認爲None,沒有縮進,設置爲正整數時,輸出的格式將按照indent指定的半角空格數縮進,至關實用。

separators 設置分隔符,默認的分隔符是(',', ': '),若是須要自定義json中的分隔符,例如調整冒號先後的空格數,能夠按照(item_separator, key_separator)的形式設置。

sort_keys 默認爲False,設爲True時,輸出結果將按照字典中的key排序。

>>> import json
>>> a = {}
>>> a['1'] = 2
>>> a['ad'] = 'ertwer'
>>> a['02'] = 'oierte'
>>> a[2] = [1, 'a']
>>> a['non_ascii'] = "青團 》 熊貓 ?"
>>> a['ss'] = a.copy()
>>> print(json.dumps(a))  # 默認參數輸出,無縮進,中文字符都被轉義
{"2": [1, "a"], "02": "oierte", "ss": {"ad": "ertwer", "2": [1, "a"], "02": "oierte", "1": 2, "non_ascii": "\u9752\u56e2 \u300b \u718a\u732b \uff1f"}, "1": 2, "ad": "ertwer", "non_ascii": "\u9752\u56e2 \u300b \u718a\u732b \uff1f"}
>>> 
>>> print(json.dumps(a, ensure_ascii=False, indent=4))  # 四空格縮進,中文字符所有正常
{
    "2": [
        1,
        "a"
    ],
    "02": "oierte",
    "ss": {
        "ad": "ertwer",
        "2": [
            1,
            "a"
        ],
        "02": "oierte",
        "1": 2,
        "non_ascii": "青團 》 熊貓 ?"
    },
    "1": 2,
    "ad": "ertwer",
    "non_ascii": "青團 》 熊貓 ?"
}
>>>
View Code

四、其它參數

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.
View Code

五、json格式化輸出:

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)
View Code

六、py對象序列化爲json的時候會接受的幾個參數:

indent: 即縮進量是幾個空格,當須要格式化輸出的時候通常設爲4個空格

if __name__ == '__main__':
    cc = {
        "name": "CC11001100",
        "age": 22,
        "money": 9.9,
        "car": "Feng-Huang Bicycle",
        "house": "祖宅",
        "girl friend": None,
        "hobby": "thinking..."
    }
    print(json.dumps(cc, indent=4))

輸出結果:
{
    "name": "CC11001100",
    "age": 22,
    "money": 9.9,
    "car": "Feng-Huang Bicycle",
    "house": "\u7956\u5b85",
    "girl friend": null,
    "hobby": "thinking..."
}
View Code

separators: 生成的json子串所使用的分隔符,就是用來代替分隔多個k/v對的,和分隔k/v的:

if __name__ == '__main__':
    cc = {
        "name": "CC11001100",
        "age": 22,
        "money": 9.9,
        "car": "Feng-Huang Bicycle",
        "house": "祖宅",
        "girl friend": None,
        "hobby": "thinking..."
    }
    print(json.dumps(cc, indent=4, separators=('', '')))

輸出結果:
  {
    "name""CC11001100""age"→22"money"→9.9"car""Feng-Huang Bicycle""house""\u7956\u5b85""girl friend"→null↓
    "hobby""thinking..."
}
View Code

 

七、總結:

1. json序列化方法:

          dumps:無文件操做            dump:序列化+寫入文件

  2. json反序列化方法:

          loads:無文件操做              load: 讀文件+反序列化

  3. json模塊序列化的數據 更通用

      picle模塊序列化的數據 僅python可用,但功能強大,能夠序列號函數

  4. json模塊能夠序列化和反序列化的  數據類型 見  python對象(obj) 與json對象的對應關係表

  5. 格式化寫入文件利用  indent = 4 

 

10.pickle模塊

一、介紹:pickle,用於python特有的類型 和 python的數據類型間進行轉換 。

二、pickle模塊的四個功能:

dumps、dump(序列化,存)、loads(反序列化,讀)、load (不只能夠序列化字典,列表...能夠把python中任意的數據類型序列化)pickle是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)
View Code

python對象(obj) 與json對象的對應關係:

 

 三、小結:

json模塊裏的dumps是將python的數據結構轉換成字符串,loads是將字符串類型轉換成python的數據結構

json模塊裏的dump是將python的數據結構轉換成字符串,而後存入到文件當中

json模塊裏的load是將文件中字符串類型轉換成python的數據結構

pickle模塊裏的dumps是將python的數據結構轉換成二進制的文件,loads是將二進制的文件轉換成python的數據結構
pickle模塊裏的dump是將python的數據結構轉換成二進制而後存入到文件中
pickle模塊裏的load是將文件中的二進制文件轉成python的數據結構 
 
 

11.shelve模塊

一、介紹:Shelve是對象持久化保存方法,將對象保存到文件裏面,缺省(即默認)的數據存儲文件是二進制的。shelve也是python提供給咱們的序列化工具,只提供給咱們一個open方法,是用key來訪問的,使用起來和字典相似。能夠做爲一個簡單的數據存儲方案。

import shelve

f=shelve.open(r'sheve.txt')
# f['stu1_info']={'name':'egon','age':18,'hobby':['piao','smoking','drinking']}
# f['stu2_info']={'name':'gangdan','age':53}
# f['school_info']={'website':'http://www.pypy.org','city':'beijing'}

print(f['stu1_info']['hobby'])
f.close()
View Code

二、實例:

# 保存數據
with shelve.open('student') as db:
    db['name'] = 'Tom'
    db['age'] = 19
    db['hobby'] = ['籃球', '看電影', '彈吉他']
    db['other_info'] = {'sno': 1, 'addr': 'xxxx'}

# 讀取數據
with shelve.open('student') as db:
    for key,value in db.items():
        print(key, ': ', value)

#輸出結果:

name :  Tom
age :  19
hobby :  ['籃球', '看電影', '彈吉他']
other_info :  {'sno': 1, 'addr': 'xxxx'}
內置數據類型操做
# 自定義class
class Student(object):
    def __init__(self, name, age, sno):
        self.name = name
        self.age = age
        self.sno = sno
    
    def __repr__(self):
        return 'Student [name: %s, age: %d, sno: %d]' % (self.name, self.age, self.sno)

# 保存數據
tom = Student('Tom', 19, 1)
jerry = Student('Jerry', 17, 2)

with shelve.open("stu.db") as db:
    db['Tom'] = tom
    db['Jerry'] = jerry

# 讀取數據
with shelve.open("stu.db") as db:
    print(db['Tom'])
    print(db['Jerry'])

輸出結果:

Student [name: Tom, age: 19, sno: 1]
Student [name: Jerry, age: 17, sno: 2]
自定義數據類型操做

 

三個序列化模塊的總結:

1. 對比

json模塊經常使用於編寫web接口,將Python數據轉換爲通用的json格式傳遞給其它系統或客戶端;也能夠用於將Python數據保存到本地文件中,缺點是明文保存,保密性差。另外,若是須要保存非內置數據類型須要編寫額外的轉換函數或自定義類。

pickle模塊和shelve模塊因爲使用其特有的序列化協議,其序列化以後的數據只能被Python識別,所以只能用於Python系統內部。另外,Python 2.x 和 Python
3.x 默認使用的序列化協議也不一樣,若是須要互相兼容須要在序列化時經過protocol參數指定協議版本。除了上面這些缺點外,pickle模塊和shelve模塊相對於json模塊的優勢在於對於自定義數據類型能夠直接序列化和反序列化,不須要編寫額外的轉換函數或類。

shelve模塊能夠看作是pickle模塊的升級版,由於shelve使用的就是pickle的序列化協議,可是shelve比pickle提供的操做方式更加簡單、方便。shelve模塊相對於其它兩個模塊在將Python數據持久化到本地磁盤時有一個很明顯的優勢就是,它容許咱們能夠像操做dict同樣操做被序列化的數據,而沒必要一次性的保存或讀取全部數據。

2. 建議

    • 須要與外部系統交互時用json模塊;
    • 須要將少許、簡單Python數據持久化到本地磁盤文件時能夠考慮用pickle模塊;
    • 須要將大量Python數據持久化到本地磁盤文件或須要一些簡單的相似數據庫的增刪改查功能時,能夠考慮用shelve模塊。

 

 

12.xml模塊

一、介紹:xml是實現不一樣語言或程序之間進行數據交換的協議,跟json差很少,但json使用起來更簡單。

xml的格式以下,就是經過<>節點來區別數據結構的:

<?xml version="1.0"?>
<data>
    <country name="Liechtenstein">
        <rank updated="yes">2</rank>
        <year>2008</year>
        <gdppc>141100</gdppc>
        <neighbor name="Austria" direction="E"/>
        <neighbor name="Switzerland" direction="W"/>
    </country>
    <country name="Singapore">
        <rank updated="yes">5</rank>
        <year>2011</year>
        <gdppc>59900</gdppc>
        <neighbor name="Malaysia" direction="N"/>
    </country>
    <country name="Panama">
        <rank updated="yes">69</rank>
        <year>2011</year>
        <gdppc>13600</gdppc>
        <neighbor name="Costa Rica" direction="W"/>
        <neighbor name="Colombia" direction="E"/>
    </country>
</data>
View Code

xml協議在各個語言裏的都 是支持的,在python中能夠用如下模塊操做xml:

# print(root.iter('year')) #全文搜索
# print(root.find('country')) #在root的子節點找,只找一個
# print(root.findall('country')) #在root的子節點找,找全部

二、xml的幾個方法:

import xml.etree.ElementTree as ET
 
tree = ET.parse("xmltest.xml")
root = tree.getroot()
print(root.tag)
 
#遍歷xml文檔
for child in root:
    print('========>',child.tag,child.attrib,child.attrib['name'])
    for i in child:
        print(i.tag,i.attrib,i.text)
 
#只遍歷year 節點
for node in root.iter('year'):
    print(node.tag,node.text)
#---------------------------------------

import xml.etree.ElementTree as ET
 
tree = ET.parse("xmltest.xml")
root = tree.getroot()
 
#修改
for node in root.iter('year'):
    new_year=int(node.text)+1
    node.text=str(new_year)
    node.set('updated','yes')
    node.set('version','1.0')
tree.write('test.xml')
 
 
#刪除node
for country in root.findall('country'):
   rank = int(country.find('rank').text)
   if rank > 50:
     root.remove(country)
 
tree.write('output.xml')


#在country內添加(append)節點year2
import xml.etree.ElementTree as ET
tree = ET.parse("a.xml")
root=tree.getroot()
for country in root.findall('country'):
    for year in country.findall('year'):
        if int(year.text) > 2000:
            year2=ET.Element('year2')
            year2.text='新年'
            year2.attrib={'update':'yes'}
            country.append(year2) #往country節點下添加子節點

tree.write('a.xml.swap')
View Code

三、xml文檔的建立:

import xml.etree.ElementTree as ET
 
 
new_xml = ET.Element("namelist")
name = ET.SubElement(new_xml,"name",attrib={"enrolled":"yes"})
age = ET.SubElement(name,"age",attrib={"checked":"no"})
sex = ET.SubElement(name,"sex")
sex.text = '33'
name2 = ET.SubElement(new_xml,"name",attrib={"enrolled":"no"})
age = ET.SubElement(name2,"age")
age.text = '19'
 
et = ET.ElementTree(new_xml) #生成文檔對象
et.write("test.xml", encoding="utf-8",xml_declaration=True)
 
ET.dump(new_xml) #打印生成的格式
View Code

 

 

13.configparser模塊

一、介紹:該模塊適用於配置文件的格式與windows  ini文件相似,能夠包含一個或多個節(section),每一個節能夠有多個參數(鍵=值)

建立:

import configparser
  
config = configparser.ConfigParser()
config["DEFAULT"] = {'ServerAliveInterval': '45',
                      'Compression': 'yes',
                     'CompressionLevel': '9'}
  
config['bitbucket.org'] = {}
config['bitbucket.org']['User'] = 'hg'
config['topsecret.server.com'] = {}
topsecret = config['topsecret.server.com']
topsecret['Host Port'] = '50022'     # mutates the parser
topsecret['ForwardX11'] = 'no'  # same here
config['DEFAULT']['ForwardX11'] = 'yes'
with open('example.ini', 'w') as configfile:
   config.write(configfile)
View Code

讀取:

import configparser

config=configparser.ConfigParser()
config.read('a.cfg')

#查看全部的標題
res=config.sections() #['section1', 'section2']
print(res)

#查看標題section1下全部key=value的key
options=config.options('section1')
print(options) #['k1', 'k2', 'user', 'age', 'is_admin', 'salary']

#查看標題section1下全部key=value的(key,value)格式
item_list=config.items('section1')
print(item_list) #[('k1', 'v1'), ('k2', 'v2'), ('user', 'egon'), ('age', '18'), ('is_admin', 'true'), ('salary', '31')]

#查看標題section1下user的值=>字符串格式
val=config.get('section1','user')
print(val) #egon

#查看標題section1下age的值=>整數格式
val1=config.getint('section1','age')
print(val1) #18

#查看標題section1下is_admin的值=>布爾值格式
val2=config.getboolean('section1','is_admin')
print(val2) #True

#查看標題section1下salary的值=>浮點型格式
val3=config.getfloat('section1','salary')
print(val3) #31.0
View Code

改寫

import configparser

config=configparser.ConfigParser()
config.read('a.cfg',encoding='utf-8')


#刪除整個標題section2
config.remove_section('section2')

#刪除標題section1下的某個k1和k2
config.remove_option('section1','k1')
config.remove_option('section1','k2')

#判斷是否存在某個標題
print(config.has_section('section1'))

#判斷標題section1下是否有user
print(config.has_option('section1',''))


#添加一個標題
config.add_section('egon')

#在標題egon下添加name=egon,age=18的配置
config.set('egon','name','egon')
config.set('egon','age',18) #報錯,必須是字符串


#最後將修改的內容寫入文件,完成最終的修改
config.write(open('a.cfg','w'))
View Code

 

14.hashlib加密模塊詳

1.介紹

算法介紹 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(),最後計算的結果是同樣的:

import hashlib
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。

摘要算法在不少地方都有普遍的應用。要注意摘要算法不是加密算法,不能用於加密(由於沒法經過摘要反推明文),只能用於防篡改,可是它的單向計算特性決定了能夠在不存儲明文口令的狀況下驗證用戶口令。
View Code

 2.檢驗文件變了沒有

import hashlib
md5_obj = hashlib.md5()
import os
filesize = os.path.getsize('filename')  #文件大小
f = open('filename','rb')
while filesize>0:
    if filesize > 1024:
        content = f.read(1024)
        filesize -= 1024
    else:
        content = f.read(filesize)
        filesize -= filesize
    md5_obj.update(content)
# for line in f:
#     md5_obj.update(line.encode('utf-8'))
md5_obj.hexdigest()
View Code

3.用戶密碼

import hashlib
# md5_obj = hashlib.md5()  未加鹽
md5_obj = hashlib.md5('nezha'.encode('utf-8')) #加鹽後(就讓你的密碼更牢固了)
md5_obj.update('123456'.encode('utf-8'))
print(md5_obj.hexdigest())
md5_obj.update('hello'.encode('utf-8'))
print(md5_obj.hexdigest())
# -----------
user = 'haiyan'
password = '123456'
md5_obj= hashlib.md5(user.encode('utf-8'))  #加鹽(哪怕被人的密碼和你的密碼同樣,
# 那你加鹽之後就只有你的用戶名對應的是你的密碼了)
md5_obj.update(password.encode('utf-8'))
print(md5_obj.hexdigest())
View Code

4.模擬撞庫破解密碼

import hashlib
passwds=[
    'alex3714',
    'alex1313',
    'alex94139413',
    'alex123456',
    '123456alex',
    'a123lex',
    ]
def make_passwd_dic(passwds):
    dic={}
    for passwd in passwds:
        m=hashlib.md5()
        m.update(passwd.encode('utf-8'))
        dic[passwd]=m.hexdigest()
    return dic

def break_code(cryptograph,passwd_dic):
    for k,v in passwd_dic.items():
        if v == cryptograph:
            print('密碼是===>\033[46m%s\033[0m' %k)

cryptograph='aee949757a2e698417463d47acac93df'
break_code(cryptograph,make_passwd_dic(passwds))
View Code

5.注意:

#要想保證hmac最終結果一致,必須保證:
#1:hmac.new括號內指定的初始key同樣
#2:不管update多少次,校驗的內容累加到一塊兒是同樣的內容

import hmac

h1=hmac.new(b'egon')
h1.update(b'hello')
h1.update(b'world')
print(h1.hexdigest())

h2=hmac.new(b'egon')
h2.update(b'helloworld')
print(h2.hexdigest())

h3=hmac.new(b'egonhelloworld')
print(h3.hexdigest())

'''
f1bf38d054691688f89dcd34ac3c27f2
f1bf38d054691688f89dcd34ac3c27f2
bcca84edd9eeb86f30539922b28f3981
'''
View Code

 

15.collections模塊

在內置數據類型(dict、list、set、tuple)的基礎上,collections模塊還提供了幾個額外的數據類型:Counter、deque、defaultdict、namedtuple和OrderedDict等。

1.namedtuple: 生成可使用名字來訪問元素內容的tuple

2.deque: 雙端隊列,能夠快速的從另一側追加和推出對象

3.Counter: 計數器,主要用來計數

4.OrderedDict: 有序字典

5.defaultdict: 帶有默認值的字典

namedtuple

咱們知道tuple能夠表示不變集合,例如,一個點的二維座標就能夠表示成:

p = (1, 2)

可是,看到(1, 2),很難看出這個tuple是用來表示一個座標的。

這時,namedtuple就派上了用場:
>>> from collections import namedtuple
>>> Point = namedtuple('Point', ['x', 'y'])
>>> p = Point(1, 2)
>>> p.x
1
>>> p.y
2

相似的,若是要用座標和半徑表示一個圓,也能夠用namedtuple定義:

namedtuple('名稱', [屬性list]):
Circle = namedtuple('Circle', ['x', 'y', 'r'])
    

deque
使用list存儲數據時,按索引訪問元素很快,可是插入和刪除元素就很慢了,由於list是線性存儲,數據量大的時候,插入和刪除效率很低。

deque是爲了高效實現插入和刪除操做的雙向列表,適合用於隊列和棧:

>>> from collections import deque
>>> q = deque(['a', 'b', 'c'])
>>> q.append('x')
>>> q.appendleft('y')
>>> q
deque(['y', 'a', 'b', 'c', 'x'])

deque除了實現list的append()和pop()外,還支持appendleft()和popleft(),這樣就能夠很是高效地往頭部添加或刪除元素。

OrderedDict
使用dict時,Key是無序的。在對dict作迭代時,咱們沒法肯定Key的順序。
若是要保持Key的順序,能夠用OrderedDict:
>>> from collections import OrderedDict
>>> d = dict([('a', 1), ('b', 2), ('c', 3)])
>>> d # dict的Key是無序的
{'a': 1, 'c': 3, 'b': 2}
>>> od = OrderedDict([('a', 1), ('b', 2), ('c', 3)])
>>> od # OrderedDict的Key是有序的
OrderedDict([('a', 1), ('b', 2), ('c', 3)])

注意,OrderedDict的Key會按照插入的順序排列,不是Key自己排序:

defaultdict
有以下值集合 [11,22,33,44,55,66,77,88,99,90...],將全部大於 66 的值保存至字典的第一個key中,將小於 66 的值保存至第二個key的值中。
即: {'k1': 大於66 , 'k2': 小於66}

li = [11,22,33,44,55,77,88,99,90]
result = {}
for row in li:
    if row > 66:
        if 'key1' not in result:
            result['key1'] = []
        result['key1'].append(row)
    else:
        if 'key2' not in result:
            result['key2'] = []
        result['key2'].append(row)
print(result)
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)


使用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'


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})
collections模塊

 hmac 模塊  它內部對咱們建立 key 和 內容 進行進一步的處理而後再加密:

1 import hmac

2 h = hmac.new('alvin'.encode('utf8'))

3 h.update('hello'.encode('utf8'))

4 print (h.hexdigest())#320df9832eab4c038b6c1d7ed73a5940

 

16.subprocess模塊

 

 

 

17.logging模塊

1.介紹:日誌是一種能夠追蹤某些軟件運行時所發生事件的方法。軟件開發人員能夠向他們的代碼中調用日誌記錄相關的方法來代表發生了某些事情。一個事件能夠用一個可包含可選變量數據的消息來描述。此外,事件也有重要性的概念,這個重要性也能夠被稱爲嚴重性級別(level)。做用:

  • 程序調試
  • 瞭解軟件程序運行狀況,是否正常
  • 軟件程序運行故障分析與問題定位

2.日誌級別:默認狀況下Python的logging模塊將日誌打印到了標準輸出中,且只顯示了大於等於WARNING級別的日誌,這說明默認的日誌級別設置爲WARNING(日誌級別等級CRITICAL > ERROR > WARNING > INFO > DEBUG),默認的日誌格式爲日誌級別:Logger名稱:用戶輸出消息。

logging.debug('調試debug')  >>>> 最詳細的日誌信息,典型應用場景是問題診斷
logging.info('消息info')    >>>>  信息詳細程度僅次於DEBUG,一般只記錄關鍵節點信息,用於確認一切都是按照咱們預期的那樣進行工做
logging.warning('警告warn')  >>>>當某些不指望的事情發生時記錄的信息(如,磁盤可用空間較低),可是此時應用程序仍是正常運行的
logging.error('錯誤error')   >>>> 因爲一個更嚴重的問題致使某些功能不能正常運行時記錄的信息
logging.critical('嚴重critical')   >>>>當發生嚴重錯誤,致使應用程序不能繼續運行時記錄的信息

 3.logging模塊的使用方式介紹

logging模塊提供了兩種記錄日誌的方式:

  • 第一種方式是使用logging提供的模塊級別的函數
  • 第二種方式是使用Logging日誌系統的四大組件

其實,logging所提供的模塊級別的日誌記錄函數也是對logging日誌系統相關類的封裝而已。

logging模塊定義的模塊級別的經常使用函數

函數 說明
logging.debug(msg, *args, **kwargs) 建立一條嚴重級別爲DEBUG的日誌記錄
logging.info(msg, *args, **kwargs) 建立一條嚴重級別爲INFO的日誌記錄
logging.warning(msg, *args, **kwargs) 建立一條嚴重級別爲WARNING的日誌記錄
logging.error(msg, *args, **kwargs) 建立一條嚴重級別爲ERROR的日誌記錄
logging.critical(msg, *args, **kwargs) 建立一條嚴重級別爲CRITICAL的日誌記錄
logging.log(level, *args, **kwargs) 建立一條嚴重級別爲level的日誌記錄
logging.basicConfig(**kwargs) 對root logger進行一次性配置

其中logging.basicConfig(**kwargs)函數用於指定「要記錄的日誌級別」、「日誌格式」、「日誌輸出位置」、「日誌文件的打開模式」等信息,其餘幾個都是用於記錄各個級別日誌的函數。

 

logging模塊的四大組件

組件 說明
loggers 提供應用程序代碼直接使用的接口
handlers 用於將日誌記錄發送到指定的目的位置
filters 提供更細粒度的日誌過濾功能,用於決定哪些日誌記錄將會被輸出(其它的日誌記錄將會被忽略)
formatters 用於控制日誌信息的最終輸出格式

說明: logging模塊提供的模塊級別的那些函數實際上也是經過這幾個組件的相關實現類來記錄日誌的,只是在建立這些類的實例時設置了一些默認值。

 4.日誌的基本配置(即logging提供的模塊級別的函數的設置)

可經過logging.basicConfig(**kwargs)函數的具體參數來更改logging模塊的基本配置,基本參數有

filename:用指定的文件名建立FiledHandler,這樣日誌會被存儲在指定的文件中。
filemode:文件打開方式,在指定了filename時使用這個參數,默認值爲「a」還可指定爲「w」。該選項要在filename指定時纔有效
format:指定handler使用的日誌顯示格式。即指定日誌輸出時所包含的字段信息以及它們的順序
datefmt:指定日期時間格式。該選項要在format中包含時間字段%(asctime)s時纔有效
level:設置rootlogger(後邊會講解具體概念)的日誌級別。
stream:用指定的stream建立StreamHandler。能夠指定輸出到sys.stderr,sys.stdout或者文件。stream和filename不能同時提供,不然會引起 異常


style:指定format格式字符串的風格,可取值爲'%'、'{'和'$',默認爲'%'

handlers:該選項若是被指定,它應該是一個建立了多個Handler的可迭代對象,這些handler將會被添加到root logger。filename、stream和handlers這三個配置項只
能有一個存在,不能同時出現2個或3個,不然會引起ValueError異常
ValueError

 日誌format格式字符串詳解:

%(name)s:Logger的名字,並不是用戶名,默認是'root',由於默認使用的是 rootLogger

%(levelno)s:日誌記錄的數字形式的日誌級別(10, 20, 30, 40, 50)

%(levelname)s:該日誌記錄的文字形式的日誌級別('DEBUG', 'INFO', 'WARNING', 'ERROR', 'CRITICAL')

%(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:用戶輸出的消息

import logging
logging.basicConfig(
    level=logging.DEBUG ,    #指定日誌器的日誌級別,多輸出一些細節
    # level = logging.WARNING  #就不用輸出那些細節了
    format = '%(name)s %(asctime)s [%(lineno)d] ---%(message)s', #指定日誌格式字符串
    # level和format也是不能變的,它是參數,不是變量
    # %(lineno)d指定代碼塊的行
    # %(name)s當前管理員的用戶
    datefmt = '%d/%m/%Y %H:%M:%S',#指定日期時間格式
    filename = 'logging_info' #自動建立了一個文件,而且把日誌寫到了文件裏

)
logging.debug('debug message')
logging.info('info message')
logging.warning('warning message')
logging.error('error message')
logging.critical('critical message')
日誌設置的列子

 

5.其餘說明

幾個要說明的內容:
  • logging.basicConfig()函數是一個一次性的簡單配置工具使,也就是說只有在第一次調用該函數時會起做用,後續再次調用該函數時徹底不會產生任何操做的,屢次調用的設置並非累加操做。
  • 日誌器(Logger)是有層級關係的,上面調用的logging模塊級別的函數所使用的日誌器是RootLogger類的實例,其名稱爲'root',它是處於日誌器層級關係最頂層的日誌器,且該實例是以單例模式存在的。
  • 若是要記錄的日誌中包含變量數據,可以使用一個格式字符串做爲這個事件的描述消息(logging.debug、logging.info等函數的第一個參數),而後將變量數據做爲第二個參數*args的值進行傳遞,如:logging.warning('%s is %d years old.', 'Tom', 10),輸出內容爲WARNING:root:Tom is 10 years old.
  • logging.debug(), logging.info()等方法的定義中,除了msg和args參數外,還有一個**kwargs參數。它們支持3個關鍵字參數: exc_info, stack_info, extra,下面對這幾個關鍵字參數做個說明。
關於exc_info, stack_info, extra關鍵詞參數的說明:
  • exc_info: 其值爲布爾值,若是該參數的值設置爲True,則會將異常異常信息添加到日誌消息中。若是沒有異常信息則添加None到日誌信息中。
  • stack_info: 其值也爲布爾值,默認值爲False。若是該參數的值設置爲True,棧信息將會被添加到日誌信息中。
  • extra: 這是一個字典(dict)參數,它能夠用來自定義消息格式中所包含的字段,可是它的key不能與logging模塊定義的字段衝突。
一個例子:

在日誌消息中添加exc_info和stack_info信息,並添加兩個自定義的字端 ip和user

LOG_FORMAT = "%(asctime)s - %(levelname)s - %(user)s[%(ip)s] - %(message)s" DATE_FORMAT = "%m/%d/%Y %H:%M:%S %p" logging.basicConfig(format=LOG_FORMAT, datefmt=DATE_FORMAT) logging.warning("Some one delete the log file.", exc_info=True, stack_info=True, extra={'user': 'Tom', 'ip':'47.98.53.222'})

輸出結果:

05/08/2017 16:35:00 PM - WARNING - Tom[47.98.53.222] - Some one delete the log file.

NoneType
Stack (most recent call last):
  File "C:/Users/wader/PycharmProjects/LearnPython/day06/log.py", line 45, in <module>
    logging.warning("Some one delete the log file.", exc_info=True, stack_info=True, extra={'user': 'Tom', 'ip':'47.98.53.222'})

6.日誌流處理流程

 

6.1logging模塊的四大組件的介紹:

6.1.1. Logger(日誌器)    須要經過處理器(handler)將日誌信息輸出到目標位置,如:文件、sys.stdout、網絡等;

Logger對象有3個任務要作:

  • 1)嚮應用程序代碼暴露幾個方法,使應用程序能夠在運行時記錄日誌消息;
  • 2)基於日誌嚴重等級(默認的過濾設施)或filter對象來決定要對哪些日誌進行後續處理;
  • 3)將日誌消息傳送給全部感興趣的日誌handlers。

Logger對象最經常使用的方法分爲兩類:配置方法 和 消息發送方法

最經常使用的配置方法以下:

方法 描述
Logger.setLevel() 設置日誌器將會處理的日誌消息的最低嚴重級別
Logger.addHandler() 和 Logger.removeHandler() 爲該logger對象添加 和 移除一個handler對象
Logger.addFilter() 和 Logger.removeFilter() 爲該logger對象添加 和 移除一個filter對象

關於Logger.setLevel()方法的說明:

內建等級中,級別最低的是DEBUG,級別最高的是CRITICAL。例如setLevel(logging.INFO),此時函數參數爲INFO,那麼該logger將只會處理INFO、WARNING、ERROR和CRITICAL級別的日誌,而DEBUG級別的消息將會被忽略/丟棄。

logger對象配置完成後,可使用下面的方法來建立日誌記錄:

方法 描述
Logger.debug(), Logger.info(), Logger.warning(), Logger.error(), Logger.critical() 建立一個與它們的方法名對應等級的日誌記錄
Logger.exception() 建立一個相似於Logger.error()的日誌消息
Logger.log() 須要獲取一個明確的日誌level參數來建立一個日誌記錄

說明:

  • Logger.exception()與Logger.error()的區別在於:Logger.exception()將會輸出堆棧追蹤信息,另外一般只是在一個exception handler中調用該方法。
  • Logger.log()與Logger.debug()、Logger.info()等方法相比,雖然須要多傳一個level參數,顯得不是那麼方便,可是當須要記錄自定義level的日誌時仍是須要該方法來完成。

那麼,怎樣獲得一個Logger對象呢?一種方式是經過Logger類的實例化方法建立一個Logger類的實例,可是咱們一般都是用第二種方式--logging.getLogger()方法。

logging.getLogger()方法有一個可選參數name,該參數表示將要返回的日誌器的名稱標識,若是不提供該參數,則其值爲'root'。若以相同的name參數值屢次調用getLogger()方法,將會返回指向同一個logger對象的引用。

  關於logger的層級結構與有效等級的說明:

  • logger的名稱是一個以'.'分割的層級結構,每一個'.'後面的logger都是'.'前面的logger的children,例如,有一個名稱爲 foo 的logger,其它名稱分別爲 foo.bar, foo.bar.baz 和 foo.bam都是 foo 的後代。
  • logger有一個"有效等級(effective level)"的概念。若是一個logger上沒有被明確設置一個level,那麼該logger就是使用它parent的level;若是它的parent也沒有明確設置level則繼續向上查找parent的parent的有效level,依次類推,直到找到個一個明確設置了level的祖先爲止。須要說明的是,root logger老是會有一個明確的level設置(默認爲 WARNING)。當決定是否去處理一個已發生的事件時,logger的有效等級將會被用來決定是否將該事件傳遞給該logger的handlers進行處理。
  • child loggers在完成對日誌消息的處理後,默認會將日誌消息傳遞給與它們的祖先loggers相關的handlers。所以,咱們沒必要爲一個應用程序中所使用的全部loggers定義和配置handlers,只須要爲一個頂層的logger配置handlers,而後按照須要建立child loggers就可足夠了。咱們也能夠經過將一個logger的propagate屬性設置爲False來關閉這種傳遞機制。

6.1.2.  Handler(處理器)      將logger建立的日誌記錄發送到合適的目的輸出,日誌器(logger)能夠設置多個處理器(handler)將同一條日誌記錄輸出到不一樣的位置

Handler對象的做用是(基於日誌消息的level)將消息分發到handler指定的位置(文件、網絡、郵件等)。Logger對象能夠經過addHandler()方法爲本身添加0個或者更多個handler對象。好比,一個應用程序可能想要實現如下幾個日誌需求:

  • 1)把全部日誌都發送到一個日誌文件中;
  • 2)把全部嚴重級別大於等於error的日誌發送到stdout(標準輸出);
  • 3)把全部嚴重級別爲critical的日誌發送到一個email郵件地址。
    這種場景就須要3個不一樣的handlers,每一個handler複雜發送一個特定嚴重級別的日誌到一個特定的位置。

一個handler中只有很是少數的方法是須要應用開發人員去關心的。對於使用內建handler對象的應用開發人員來講,彷佛惟一相關的handler方法就是下面這幾個配置方法:

方法 描述
Handler.setLevel() 設置handler將會處理的日誌消息的最低嚴重級別
Handler.setFormatter() 爲handler設置一個格式器對象
Handler.addFilter() 和 Handler.removeFilter() 爲handler添加 和 刪除一個過濾器對象

須要說明的是,應用程序代碼不該該直接實例化和使用Handler實例。由於Handler是一個基類,它只定義了素有handlers都應該有的接口,同時提供了一些子類能夠直接使用或覆蓋的默認行爲。下面是一些經常使用的Handler:

 

Handler 描述
logging.StreamHandler 將日誌消息發送到輸出到Stream,如std.out, std.err或任何file-like對象。
logging.FileHandler 將日誌消息發送到磁盤文件,默認狀況下文件大小會無限增加
logging.handlers.RotatingFileHandler 將日誌消息發送到磁盤文件,並支持日誌文件按大小切割
logging.hanlders.TimedRotatingFileHandler 將日誌消息發送到磁盤文件,並支持日誌文件按時間切割
logging.handlers.HTTPHandler 將日誌消息以GET或POST的方式發送給一個HTTP服務器
logging.handlers.SMTPHandler 將日誌消息發送給一個指定的email地址
logging.NullHandler 該Handler實例會忽略error messages,一般被想使用logging的library開發者使用來避免'No handlers could be found for logger XXX'信息的出現。

 

6.1.3  Filter(過濾器)   實現日誌過濾,從而只保留感興趣的日誌

Filter能夠被Handler和Logger用來作比level更細粒度的、更復雜的過濾功能。Filter是一個過濾器基類,它只容許某個logger層級下的日誌事件經過過濾。該類定義以下:

class logging.Filter(name='') filter(record)

好比,一個filter實例化時傳遞的name參數值爲'A.B',那麼該filter實例將只容許名稱爲相似以下規則的loggers產生的日誌記錄經過過濾:'A.B','A.B,C','A.B.C.D','A.B.D',而名稱爲'A.BB', 'B.A.B'的loggers產生的日誌則會被過濾掉。若是name的值爲空字符串,則容許全部的日誌事件經過過濾。

filter方法用於具體控制傳遞的record記錄是否能經過過濾,若是該方法返回值爲0表示不能經過過濾,返回值爲非0表示能夠經過過濾。

說明:

  • 若是有須要,也能夠在filter(record)方法內部改變該record,好比添加、刪除或修改一些屬性。
  • 咱們還能夠經過filter作一些統計工做,好比能夠計算下被一個特殊的logger或handler所處理的record數量等。

6.1.4.  formatter(格式器) 實現同一條日誌以不一樣的格式輸出到不一樣的地方

Formater對象用於配置日誌信息的最終順序、結構和內容。與logging.Handler基類不一樣的是,應用代碼能夠直接實例化Formatter類。另外,若是你的應用程序須要一些特殊的處理行爲,也能夠實現一個Formatter的子類來完成。

Formatter類的構造方法定義以下:

logging.Formatter.__init__(fmt=None, datefmt=None, style='%')

可見,該構造方法接收3個可選參數:

  • fmt:指定消息格式化字符串,若是不指定該參數則默認使用message的原始值
  • datefmt:指定日期格式字符串,若是不指定該參數則默認使用"%Y-%m-%d %H:%M:%S"
  • style:Python 3.2新增的參數,可取值爲 '%', '{'和 '$',若是不指定該參數則默認使用'%'

 

6.2日誌流處理流程:

  • 1)(在用戶代碼中進行)日誌記錄函數調用,如:logger.info(...),logger.debug(...)等;
  • 2)判斷要記錄的日誌級別是否知足日誌器設置的級別要求(要記錄的日誌級別要大於或等於日誌器設置的級別纔算知足要求),若是不知足則該日誌記錄會被丟棄並終止後續的操做,若是知足則繼續下一步操做;
  • 3)根據日誌記錄函數調用時摻入的參數,建立一個日誌記錄(LogRecord類)對象;
  • 4)判斷日誌記錄器上設置的過濾器是否拒絕這條日誌記錄,若是日誌記錄器上的某個過濾器拒絕,則該日誌記錄會被丟棄並終止後續的操做,若是日誌記錄器上設置的過濾器不拒絕這條日誌記錄或者日誌記錄器上沒有設置過濾器則繼續下一步操做--將日誌記錄分別交給該日誌器上添加的各個處理器;
  • 5)判斷要記錄的日誌級別是否知足處理器設置的級別要求(要記錄的日誌級別要大於或等於該處理器設置的日誌級別纔算知足要求),若是不知足記錄將會被該處理器丟棄並終止後續的操做,若是知足則繼續下一步操做;
  • 6)判斷該處理器上設置的過濾器是否拒絕這條日誌記錄,若是該處理器上的某個過濾器拒絕,則該日誌記錄會被當前處理器丟棄並終止後續的操做,若是當前處理器上設置的過濾器不拒絕這條日誌記錄或當前處理器上沒有設置過濾器測繼續下一步操做;
  • 7)若是能到這一步,說明這條日誌記錄通過了層層關卡容許被輸出了,此時當前處理器會根據自身被設置的格式器(若是沒有設置則使用默認格式)將這條日誌記錄進行格式化,最後將格式化後的結果輸出到指定位置(文件、網絡、類文件的Stream等);
  • 8)若是日誌器被設置了多個處理器的話,上面的第5-8步會執行屢次;
  • 9)這裏纔是完整流程的最後一步:判斷該日誌器輸出的日誌消息是否須要傳遞給上一級logger(以前提到過,日誌器是有層級關係的)的處理器,若是propagate屬性值爲1則表示日誌消息將會被輸出處處理器指定的位置,同時還會被傳遞給parent日誌器的handlers進行處理直到當前日誌器的propagate屬性爲0中止,若是propagate值爲0則表示不向parent日誌器的handlers傳遞該消息,到此結束。

可見,一條日誌信息要想被最終輸出須要依次通過如下幾回過濾:

  • 日誌器等級過濾;
  • 日誌器的過濾器過濾;
  • 日誌器的處理器等級過濾;
  • 日誌器的處理器的過濾器過濾;

須要說明的是: 關於上面第9個步驟,若是propagate值爲1,那麼日誌消息會直接傳遞交給上一級logger的handlers進行處理,此時上一級logger的日誌等級並不會對該日誌消息進行等級過濾。

 

'''
critical=50
error =40
warning =30
info = 20
debug =10
'''


import logging

#一、logger對象:負責產生日誌,而後交給Filter過濾,而後交給不一樣的Handler輸出
logger=logging.getLogger(__file__)

#二、Filter對象:不經常使用,略

#三、Handler對象:接收logger傳來的日誌,而後控制輸出
h1=logging.FileHandler('t1.log') #打印到文件
h2=logging.FileHandler('t2.log') #打印到文件
h3=logging.StreamHandler() #打印到終端

#四、Formatter對象:日誌格式
formmater1=logging.Formatter('%(asctime)s - %(name)s - %(levelname)s -%(module)s:  %(message)s',
                    datefmt='%Y-%m-%d %H:%M:%S %p',)

formmater2=logging.Formatter('%(asctime)s :  %(message)s',
                    datefmt='%Y-%m-%d %H:%M:%S %p',)

formmater3=logging.Formatter('%(name)s %(message)s',)


#五、爲Handler對象綁定格式
h1.setFormatter(formmater1)
h2.setFormatter(formmater2)
h3.setFormatter(formmater3)

#六、將Handler添加給logger並設置日誌級別
logger.addHandler(h1)
logger.addHandler(h2)
logger.addHandler(h3)
logger.setLevel(10)

#七、測試
logger.debug('debug')
logger.info('info')
logger.warning('warning')
logger.error('error')
logger.critical('critical')
列子

 

"""
logging配置
"""

import os
import logging.config

# 定義三種日誌輸出格式 開始

standard_format = '[%(asctime)s][%(threadName)s:%(thread)d][task_id:%(name)s][%(filename)s:%(lineno)d]' \
                  '[%(levelname)s][%(message)s]' #其中name爲getlogger指定的名字

simple_format = '[%(levelname)s][%(asctime)s][%(filename)s:%(lineno)d]%(message)s'

id_simple_format = '[%(levelname)s][%(asctime)s] %(message)s'

# 定義日誌輸出格式 結束

logfile_dir = os.path.dirname(os.path.abspath(__file__))  # log文件的目錄

logfile_name = 'all2.log'  # log文件名

# 若是不存在定義的日誌目錄就建立一個
if not os.path.isdir(logfile_dir):
    os.mkdir(logfile_dir)

# log文件的全路徑
logfile_path = os.path.join(logfile_dir, logfile_name)

# log配置字典
LOGGING_DIC = {
    'version': 1,
    'disable_existing_loggers': False,
    'formatters': {
        'standard': {
            'format': standard_format
        },
        'simple': {
            'format': simple_format
        },
    },
    'filters': {},
    'handlers': {
        #打印到終端的日誌
        'console': {
            'level': 'DEBUG',
            'class': 'logging.StreamHandler',  # 打印到屏幕
            'formatter': 'simple'
        },
        #打印到文件的日誌,收集info及以上的日誌
        'default': {
            'level': 'DEBUG',
            'class': 'logging.handlers.RotatingFileHandler',  # 保存到文件
            'formatter': 'standard',
            'filename': logfile_path,  # 日誌文件
            'maxBytes': 1024*1024*5,  # 日誌大小 5M
            'backupCount': 5,
            'encoding': 'utf-8',  # 日誌文件的編碼,不再用擔憂中文log亂碼了
        },
    },
    'loggers': {
        #logging.getLogger(__name__)拿到的logger配置
        '': {
            'handlers': ['default', 'console'],  # 這裏把上面定義的兩個handler都加上,即log數據既寫入文件又打印到屏幕
            'level': 'DEBUG',
            'propagate': True,  # 向上(更高level的logger)傳遞
        },
    },
}


def load_my_logging_cfg():
    logging.config.dictConfig(LOGGING_DIC)  # 導入上面定義的logging配置
    logger = logging.getLogger(__name__)  # 生成一個log實例
    logger.info('It works!')  # 記錄該文件的運行狀態

if __name__ == '__main__':
    load_my_logging_cfg()
列子

 

Logger與Handler的級別

logger是第一級過濾,而後才能到handler,咱們能夠給logger和handler同時設置level,可是須要注意的是

驗證
import logging


form=logging.Formatter('%(asctime)s - %(name)s - %(levelname)s -%(module)s:  %(message)s',
                    datefmt='%Y-%m-%d %H:%M:%S %p',)

ch=logging.StreamHandler()

ch.setFormatter(form)
# ch.setLevel(10)
ch.setLevel(20)

l1=logging.getLogger('root')
# l1.setLevel(20)
l1.setLevel(10)
l1.addHandler(ch)

l1.debug('l1 debug')
View Code
注意注意注意:


#一、有了上述方式咱們的好處是:全部與logging模塊有關的配置都寫到字典中就能夠了,更加清晰,方便管理


#二、咱們須要解決的問題是:
    1、從字典加載配置:logging.config.dictConfig(settings.LOGGING_DIC)

    2、拿到logger對象來產生日誌
    logger對象都是配置到字典的loggers 鍵對應的子字典中的
    按照咱們對logging模塊的理解,要想獲取某個東西都是經過名字,也就是key來獲取的
    因而咱們要獲取不一樣的logger對象就是
    logger=logging.getLogger('loggers子字典的key名')

    
    但問題是:若是咱們想要不一樣logger名的logger對象都共用一段配置,那麼確定不能在loggers子字典中定義n個key   
 'loggers': {    
        'l1': {
            'handlers': ['default', 'console'],  #
            'level': 'DEBUG',
            'propagate': True,  # 向上(更高level的logger)傳遞
        },
        'l2: {
            'handlers': ['default', 'console' ], 
            'level': 'DEBUG',
            'propagate': False,  # 向上(更高level的logger)傳遞
        },
        'l3': {
            'handlers': ['default', 'console'],  #
            'level': 'DEBUG',
            'propagate': True,  # 向上(更高level的logger)傳遞
        },

}

    
#咱們的解決方式是,定義一個空的key
    'loggers': {
        '': {
            'handlers': ['default', 'console'], 
            'level': 'DEBUG',
            'propagate': True, 
        },

}

這樣咱們再取logger對象時
logging.getLogger(__name__),不一樣的文件__name__不一樣,這保證了打印日誌時標識信息不一樣,可是拿着該名字去loggers裏找key名時卻發現找不到,因而默認使用key=''的配置
!!!關於如何拿到logger對象的詳細解釋!!!
"""
MyLogging Test
"""

import time
import logging
import my_logging  # 導入自定義的logging配置

logger = logging.getLogger(__name__)  # 生成logger實例


def demo():
    logger.debug("start range... time:{}".format(time.time()))
    logger.info("中文測試開始。。。")
    for i in range(10):
        logger.debug("i:{}".format(i))
        time.sleep(0.2)
    else:
        logger.debug("over range... time:{}".format(time.time()))
    logger.info("中文測試結束。。。")

if __name__ == "__main__":
    my_logging.load_my_logging_cfg()  # 在你程序文件的入口加載自定義logging配置
    demo()
View Code

 

 

 

18.re正則模塊

1.介紹:正則表達式自己是一種小型的、高度專業化的編程語言,而在python中,經過內嵌集成re模塊,程序員們能夠直接調用來實現正則匹配。正則表達式模式被編譯成一系列的字節碼,而後由用C編寫的匹配引擎執行。

2.經常使用匹配模式(元字符)及預約義字符集表

元字符表

.

須要字符串裏徹底符合,匹配規則,就匹配,(規則裏的.元字符)能夠是任何一個字符,匹配任意除換行符"\n"外的字符(在DOTALL模式中也能匹配換行符)

\

1.反斜槓後邊跟元字符去除特殊功能;(即將特殊字符轉義成普通字符),2.反斜槓後邊跟普通字符實現特殊功能;(即預約義字符),3.\2引用序號對應的字組

*

須要字符串裏徹底符合,匹配規則,就匹配,(規則裏的*元字符)前面的一個字符能夠是0個或多個本來字符,匹配前一個字符0或屢次,貪婪匹配前導字符有多少個就匹配多少個很貪婪,若是規則裏只有一個分組,儘可能避免用*不然會有可能匹配出空字符串

+

須要字符串裏徹底符合,匹配規則,就匹配,(規則裏的+元字符)前面的一個字符能夠是1個或多個本來字符,匹配前一個字符1次或無限次,貪婪匹配前導字符有多少個就匹配多少個很貪婪

?

須要字符串裏徹底符合,匹配規則,就匹配,(規則裏的?元字符)前面的一個字符能夠是0個或1個本來字符,匹配一個字符0次或1次,還有一個功能是能夠防止貪婪匹配,詳情見防貪婪匹配

^

字符串開始位置與匹配規則符合就匹配,不然不匹配,匹配字符串開頭。在多行模式中匹配每一行的開頭,^元字符若是寫到[]字符集裏就是反取

$

字符串結束位置與匹配規則符合就匹配,不然不匹配,匹配字符串末尾,在多行模式中匹配每一行的末尾

|

|或,或就是先後其中一個符合就匹配

{}

須要字符串裏徹底符合,匹配規則,就匹配,(規則裏的 {} 元字符)前面的一個字符,是自定義字符數,位數的本來字符,{m}匹配前一個字符m次,{m,n}匹配前一個字符m至n次,若省略n,則匹配m至無限次,{0,}匹配前一個字符0或屢次,等同於*元字符,{+,}匹配前一個字符1次或無限次,等同於+元字符,{0,1}匹配前一個字符0次或1次,等同於?元字符

[]

須要字符串裏徹底符合,匹配規則,就匹配,(規則裏的 [] 元字符)對應位置是[]裏的任意一個字符就匹配,字符集。對應的位置能夠是字符集中任意字符。字符集中的字符能夠逐個列出,也能夠給出範圍,如[abc]或[a-c]。[^abc]表示取反,即非abc。全部特殊字符在字符集中都失去其原有的特殊含義。用\反斜槓轉義恢復特殊字符的特殊含義。

()

也就是分組匹配,()裏面的爲一個組也能夠理解成一個總體,若是()後面跟的是特殊元字符如   (adc)*   那麼*控制的前導字符就是()裏的總體內容,再也不是前導一個字符

 

預約義字符集表(能夠寫在字符集[...]中) 

\d

\d匹配任何十進制數,它至關於類[0-9],\d+若是須要匹配一位或者多位數的數字時用

a\bc

a1c

\D

\D匹配任何非數字字符,它至關於類[^0-9]

a\Dc

abc

\s

\s匹配任何空白字符,它至關於類[\t\n\r\f\v]

a\sc

a c

\S

\S匹配任何非空白字符,它至關於類[^\t\n\r\f\v]

a\Sc

abc

\w

\w匹配包括下劃線在內任何字母數字字符,它至關於類[a-zA-Z0-9_]

a\wc

abc

\W

\W匹配非任何字母數字字符包括下劃線在內,它至關於類[^a-zA-Z0-9_]

a\Wc

a c

\A

僅匹配字符串開頭,同^

\Aabc

abc

\Z

僅匹配字符串結尾,同$

abc\Z

abc

\b

b匹配一個單詞邊界,也就是指單詞和空格間的位置

\babc\b
a\b!bc

空格abc空格
a!bc

\B

[^\b]

a\Bbc

abc

 

3.元字符詳解

^元字符

字符串開始位置與匹配規則符合就匹配,不然不匹配,匹配字符串開頭。在多行模式中匹配每一行的開頭^元字符若是寫到[]字符集裏就是反取

import re   #第一步,要引入re模塊
a = re.findall("^匹配規則", "匹配規則這個字符串是否匹配")   #字符串開始位置與匹配規則符合就匹配,不然不匹配
print(a)  #以列表形式返回匹配到的字符串
#打印出 ['匹配規則']
^元字符

[^a-z]反取,匹配出除字母外的字符,^元字符若是寫到字符集裏就是反取

import re   #第一步,要引入re模塊
a = re.findall("[^a-z]", "匹配s規則這s個字符串是否s匹配f規則則re則則則")   #反取,匹配出除字母外的字符
print(a)  #以列表形式返回匹配到的字符串
#打印出 ['匹', '配', '規', '則', '這', '個', '字', '符', '串', '是', '否', '匹', '配', '規', '則', '則', '則', '則', '則']
View Code

$元字符

字符串結束位置與匹配規則符合就匹配,不然不匹配,匹配字符串末尾,在多行模式中匹配每一行的末尾

import re   #第一步,要引入re模塊
a = re.findall("匹配規則$", "這個字符串是否匹配規則")   #字符串結束位置與匹配規則符合就匹配,不然不匹配
print(a)  #以列表形式返回匹配到的字符串
#打印出 ['匹配規則']
$元字符

*元字符

須要字符串裏徹底符合,匹配規則,就匹配,(規則裏的*元字符)前面的一個字符能夠是0個或多個本來字符,匹配前一個字符0或屢次,貪婪匹配前導字符有多少個就匹配多少個很貪婪,若是規則裏只有一個分組,儘可能避免用*不然會有可能匹配出空字符串

import re   #第一步,要引入re模塊
a = re.findall("匹配規則*", "這個字符串是否匹配規則則則則則")   #須要字符串裏徹底符合,匹配規則,就匹配,(規則裏的*元字符)前面的一個字符能夠是0或多個本來字符
print(a)  #以列表形式返回匹配到的字符串
#打印出 ['匹配規則則則則則']
*元字符

+元字符

須要字符串裏徹底符合,匹配規則,就匹配,(規則裏的+元字符)前面的一個字符能夠是1個或多個本來字符

匹配前一個字符1次或無限次,貪婪匹配前導字符有多少個就匹配多少個很貪婪

 

 

?元字符,和防止貪婪匹配

須要字符串裏徹底符合,匹配規則,就匹配,(規則裏的?元字符)前面的一個字符能夠是0個或1個本來字符

匹配一個字符0次或1次

還有一個功能是能夠防止貪婪匹配,詳情見防貪婪匹配

 

{}元字符,範圍

須要字符串裏徹底符合,匹配規則,就匹配,(規則裏的 {} 元字符)前面的一個字符,是自定義字符數,位數的本來字符

{m}匹配前一個字符m次,{m,n}匹配前一個字符m至n次,若省略n,則匹配m至無限次

{0,}匹配前一個字符0或屢次,等同於*元字符
{+,}匹配前一個字符1次或無限次,等同於+元字符
{0,1}匹配前一個字符0次或1次,等同於?元字符

 

[]元字符,字符集

須要字符串裏徹底符合,匹配規則,就匹配,(規則裏的 [] 元字符)對應位置是[]裏的任意一個字符就匹配

字符集。對應的位置能夠是字符集中任意字符。字符集中的字符能夠逐個列出,也能夠給出範圍,如[abc]或[a-c]。[^abc]表示取反,即非abc。
全部特殊字符在字符集中都失去其原有的特殊含義。用\反斜槓轉義恢復特殊字符的特殊含義  



[^]非,反取,匹配出除[^]裏面的字符,^元字符若是寫到字符集裏就是反取
 

 

 

預約義字符詳解

\d匹配任何十進制數,它至關於類[0-9]

 

\d+若是須要匹配一位或者多位數的數字時用

 

\D匹配任何非數字字符,它至關於類[^0-9]

 

\s匹配任何空白字符,它至關於類[\t\n\r\f\v]

 

\S匹配任何非空白字符,它至關於類[^\t\n\r\f\v]

 

\w匹配包括下劃線在內任何字母數字字符,它至關於類[a-zA-Z0-9_]

 

\W匹配非任何字母數字字符包括下劃線在內,它至關於類[^a-zA-Z0-9_]

 

 

 

re模塊中經常使用功能函數

相關文章
相關標籤/搜索