python基礎篇14-模塊

模塊node

模塊(modules)的概念:python

在計算機程序的開發過程當中,隨着程序代碼越寫越多,在一個文件裏代碼就會愈來愈長,愈來愈不容易維護。linux

爲了編寫可維護的代碼,咱們把不少函數分組,分別放到不一樣的文件裏,這樣,每一個文件包含的代碼就相對較少,不少編程語言都採用這種組織代碼的方式。在Python中,一個.py文件就稱之爲一個模塊(Module)。git

使用模塊有什麼好處?程序員

最大的好處是大大提升了代碼的可維護性。web

其次,編寫代碼沒必要從零開始。當一個模塊編寫完畢,就能夠被其餘地方引用。咱們在編寫程序的時候,也常常引用其餘模塊,包括Python內置的模塊和來自第三方的模塊。正則表達式

因此,模塊一共三種:算法

    • python標準庫
    • 第三方模塊
    • 應用程序自定義模塊

另外,使用模塊還能夠避免函數名和變量名衝突。相同名字的函數和變量徹底能夠分別存在不一樣的模塊中,所以,咱們本身在編寫模塊時,沒必要考慮名字會與其餘模塊衝突。可是也要注意,儘可能不要與內置函數名字衝突。shell

 

 模塊導入的方法:編程

存在如下兩個.py文件,都位於F:\\code\\day18路徑下:

calculate.py

1 print('ok')
2 
3 x = 3
4 def add(x,y):
5     return x+y
6 
7 def sub(x,y):
8     return x-y

 

bin.py

1.import語句:

 1 import sys
 2 
 3 #搜索路徑:
 4 print(sys.path)  #['F:\\code\\day18', 'F:\\code', 'E:\\soft_install\\python\\python3.5\\python35.zip', 'E:\\soft_install\\python\\python3.5\\DLLs', 'E:\\soft_install\\python\\python3.5\\lib', 'E:\\soft_install\\python\\python3.5', 'E:\\soft_install\\python\\python3.5\\lib\\site-packages']
 5 
 6 import calculate  #做用是解釋器經過搜索路徑找到calculate.py模塊後,將calculate.py中全部代碼解釋完成後(即執行模塊)賦值給calculate對象,此時calculate.py裏的全部方法以及變量都要經過calculate對象來調用。
 7 print(calculate.add(1,2))  #調用calculate.py模塊的add方法
 8 # 輸出:
 9 # ok
10 # 3
11 
12 print(x)  #報錯:NameError: name 'x' is not defined
13 print(calculate.x)  #3

2.from....import....語句:

1 from calculate import add  也能夠只導入模塊的部分方法,則模塊中的其它方法將沒法調用
2 print(add(1,2))  #調用calculate.py模塊的add方法
3 # 輸出:
4 # ok
5 # 3
6 
7 print(sub(1,2))  #報錯,NameError: name 'sub' is not defined

3.from....import* 語句:

 1 from calculate import *  
 2 print(add(1,2)) #和1的區別是無需經過calculate.add()來調用函數
 3 print(sub(1,2))
 4 print(x)  
 5 
 6 # 輸出:
 7 # ok
 8 # 3
 9 # -1
10 # 3

這提供了一個簡單的方法來導入一個模塊中的全部項目。然而這種聲明不應被過多地使用。大多數狀況, Python程序員不使用這種方法,由於引入的其它來源的命名,極可能覆蓋了已有的定義。

4.運行本質:

1 # import calculate
2 # from calculate import add 

不管1仍是2,首先經過sys.path找到calculate.py,而後執行calculate.py(所有執行),區別是1會將calculate這個變量名加載到名字空間,而2只會將add這個變量名加載進來。

5.自定義方法名

1 from calculate import add as plus
2 
3 add(1,2)  #報錯
4 plus(1,2) #這是須要經過plus來調用方法

模塊導入流程:

1. 先從sys.modules裏查看模塊是否已經被導入

2. 模塊若是沒有被導入,就依據sys.path路徑尋找模塊

3. 若是在sys.path路徑下找到模塊就導入模塊

4. 建立這個模塊的命名空間,執行模塊文件(.py文件),並把模塊文件中的名字都放到該命名空間裏。

 

包(package)

做用:若是不一樣的人編寫的模塊名相同怎麼辦?爲了不模塊名衝突,Python又引入了按目錄來組織模塊的方法,稱爲包(Package)。舉個例子,一個abc.py的文件就是一個名字叫abc的模塊,一個xyz.py的文件就是一個名字叫xyz的模塊。如今,假設咱們的abcxyz這兩個模塊名字與其餘模塊衝突了,因而咱們能夠經過包來組織模塊,避免衝突;

注意:每個包目錄下面都會有一個__init__.py的文件,這個文件是必須存在的,不然,Python就把這個目錄當成普通目錄(文件夾),而不是一個包。__init__.py能夠是空文件,也能夠有Python代碼,由於__init__.py自己就是一個模塊,而它的模塊名就是對應包的名字;調用包就是執行包下的__init__.py文件(即import PACKGE 即執行包下的__init__.py文件)

 

  • 存在以下目錄結構:

 

 在bin.py模塊中調用web下的logger模塊:

1 from web import logger
2 logger.logger()   #在bin.py模塊中就能夠實現調用web下logger模塊中的方法了

 

  •  存在以下目錄結構:

 

在bin.py模塊中調用web下web2下的logger模塊:

1 from web.web2 mport logger
2 logger.logger()

只調用logger下的某些方法:

1 from web.web2.logger import logger  #調用logger模塊下的logger方法
2 logger.logger()

 

  • BASE_DIR引入:

存在以下目錄結構:

main.py:

1 #import logger   #若是這樣寫,在bin.py中調用main方法時會報沒法找到logger的錯誤,應該改爲以下的方式
2 from module import logger 
3 def main:
4     logger.logger()

 

 logger.py

1 def logger:
2     print('logger')

 

若是修改bin.py是程序的入口,在bin.py中如何調用main.py中的main函數?

bin.py

1 from module import main
2 main.main()  #這句話相似於將main方法中的全部代碼複製至該模塊(bin.py)下

注意:bin.py在pycharm中能夠正常執行,由於在pycharm中在sys.path中將包bin的父目錄的路徑也添加到搜索路徑,因此在pycharm中能夠搜索到module;可是再命令行下將報錯(由於在bin.py模塊下沒法找到module包)。

解決:

__file__:獲取程序的相對路徑,如

print(__file__)  #輸出bin.py (在pycharm中打印顯示時會將該相對路徑轉化爲絕對路徑,其餘環境中仍是相對路徑)

print(os.path.abspath(__file__)) # C:\\Users\\Administrator\\PycharmProjects\\ATM\\bin  (根據相對路徑找到絕對路徑)

BASE_DIR=(os.path.abspath(os.path.abspath(__file__)))  #C:\\Users\\Administrator\\PycharmProjects\\ATM

優化後的bin.py的代碼以下:將程序移植到任何環境下都能執行

1 import sys,os
2 BASE_DIR=(os.path.abspath(os.path.abspath(__file__))) 
3 sys.path.append(BASE_DIR)
4 
5 from module import main
6 
7 main.main()

 

if __name__ =='__main__':

若是咱們是直接執行某個.py文件的時候,在該文件中」__name__ == '__main__'「是True,可是咱們若是從另一個.py文件經過import導入該文件的時候,這時__name__的值就是咱們這個py文件的名字而不是__main__;這個功能還有一個用處:調試代碼的時候,在」if __name__ == '__main__'「中加入一些咱們的調試代碼,咱們可讓外部模塊調用的時候不執行咱們的調試代碼,可是若是咱們想排查問題的時候,直接執行該模塊文件,調試代碼可以正常運行!

例子:

存在如下目錄結構:

foo.py代碼以下:功能模塊

def hello:

    print('hello')

hello()   #調試代碼,單獨執行foo.py時會執行hello()方法,外部調用foo模塊時也會執行hello()方法

bin.py代碼以下:調用模塊

import foo

foo.hello()

輸出:輸出了兩次hello

hello

hello

優化:

foo.py代碼以下:

def hello:

    print('hello')

#print(__main__)   在該模塊下執行輸出的是__main__,則if __name__='__main__'就爲True,就會執行調試代碼;在模塊調用時結果爲foo(即爲模塊名),則在模塊調用時if __name__!='__main__',則就不會執行調試代碼

if __name__='__main__':

    hello()   #調試代碼,單獨執行foo.py時會執行hello()方法,外部調用foo模塊時將不會執行hello()方法

bin.py代碼以下:調用模塊

import foo

foo.hello()

輸出:只輸出一次hello

hello

 

time模塊

 1 import time
 2 #print(help(time))  查看幫助
 3 
 4 print(time.time())    #1517193182.0534253   時間戳(s),unix誕生以來開始計算
 5 time.sleep(3)         #休眠3s
 6 print(time.clock())   #7.551609587825597e-07  計算cpu執行時間(不包括上面的3s)
 7 print(time.gmtime())  #結構化時間:time.struct_time(tm_year=2018, tm_mon=1, tm_mday=29, tm_hour=2, tm_min=36, tm_sec=5, tm_wday=0, tm_yday=29, tm_isdst=0) 即UTC(世界標準)時間,和北京時間差8h
 8 print(time.localtime())  #本地時間:time.struct_time(tm_year=2018, tm_mon=1, tm_mday=29, tm_hour=10, tm_min=45, tm_sec=10, tm_wday=0, tm_yday=29, tm_isdst=0)
 9 
10 #print(time.strftime(format,p_tuple))  將結構化時間以字符串時間形式輸出
11 print(time.strftime("%Y-%m-%d %H:%M:%S" ))  #字符串時間即自定義格式輸出日期 2018-01-29 10:55:02
12 struct_time=time.localtime()
13 print(time.strftime("%Y-%m-%d %H:%M:%S",struct_time))  #將結構化時間以字符串時間輸出:2018-01-29 10:58:51
14 
15 #time.strptime(string,format)  將字符串時間以結構化時間輸出
16 print(time.strptime("2018-01-29 10:58:51","%Y-%m-%d %H:%M:%S"))  #time.struct_time(tm_year=2018, tm_mon=1, tm_mday=29, tm_hour=10, tm_min=58, tm_sec=51, tm_wday=0, tm_yday=29, tm_isdst=-1)
17 #取某個時間值:
18 a=time.strptime("2018-01-29 10:58:51","%Y-%m-%d %H:%M:%S")
19 print(a.tm_hour)   #10
20 print(a.tm_mon)    #1
21 
22 #time.ctime(seconds)
23 print(time.ctime())  #取當前時間:Mon Jan 29 11:11:09 2018
24 print(time.ctime(234566))  #將給定的時間以看得懂的方式輸出(unix誕生以來的時間開始計算)
25 
26 #time.mktime(p_tuple)
27 a=time.localtime()
28 print(time.mktime(a))  #將本地時間轉化爲時間戳:1517195833.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)

 

datatime模塊

1 import datetime
2 print(datetime.datetime.now())   #2018-01-29 11:20:48.342246

 

 

random模塊-隨機數模塊

 1 import random
 2 print(random.random())  #取0-1內的隨機數
 3 print(random.randint(1,8))  #1-8內的隨機數,包括8
 4 print(random.choice("hello")) #在給定的字符串選取隨機數
 5 print(random.choice([1,2,3,4,5])) #也能夠放列表
 6 print(random.sample([1,2,[3,4]],2)) #在序列中隨機選2個,[2, [3, 4]]
 7 print(random.randrange(1,10))  #取1-10的數,不包括10
 8 
 9 
10 #生成隨機驗證碼
11 import random
12 checkcode = ''
13 for i in range(4):
14     current = random.randrange(0,4)
15     if current != i:
16         temp = chr(random.randint(65,90))
17     else:
18         temp = random.randint(0,9)
19     checkcode += str(temp)
20 print checkcode

 

 

os模塊-和操做系統交互的模塊

提供對操做系統進行調用的接口。

r:以字符原意思輸出。

 1 os.getcwd() 獲取當前工做目錄,即當前python腳本工做的目錄路徑;
 2 os.chdir("dirname")  改變當前腳本工做目錄;至關於shell下cd ;os.chdir(r'F:\code')    # r:取消全部轉義
 3 os.curdir  返回當前目錄: ('.')
 4 os.pardir  獲取當前目錄的父目錄字符串名:('..')
 5 os.makedirs('dirname1/dirname2')      可生成多層遞歸目錄;os.makedirs(r'abc\lriwu\alen')
 6 os.removedirs('dirname1/dirname2')    若目錄爲空,則刪除,並遞歸到上一級目錄,如若也爲空,則刪除,依此類推  ;s.removedirs(r'abc\lriwu\alen')
 7 os.mkdir('dirname')    生成單級目錄;至關於shell中mkdir dirname
 8 os.rmdir('dirname')    刪除單級空目錄,若目錄不爲空則沒法刪除,報錯;至關於shell中rmdir dirname
 9 os.listdir('dirname')    列出指定目錄下的全部文件和子目錄,包括隱藏文件,並以列表方式打印
10 os.remove()  刪除一個文件
11 os.rename("oldname","newname")  重命名文件/目錄
12 os.stat('path/filename')  獲取文件/目錄信息    os.stat('path/filename').st_size   獲取文件大小,返回值是int類型 13 os.sep    輸出操做系統特定的路徑分隔符,win下爲"\",Linux下爲"/"
14 os.linesep    輸出當前平臺使用的行終止符,win下爲"\t\n",Linux下爲"\n"
15 os.pathsep    輸出用於分割文件路徑的字符串,如環境變量;windows:';'  linux:':'
16 os.name    輸出字符串指示當前使用平臺。win->'nt'; Linux->'posix'
17 os.system("bash command")  運行shell命令,直接顯示,無返回值  os.system("dir")
ret = os.popen("dir").read() 運行shell命令,不顯示,有返回值
print(ret)
18 os.environ 獲取系統環境變量 19 os.path.abspath(path) 返回path規範化的絕對路徑;print(os.path.abspath('./os.py')) # D:\code\os.py 20 os.path.split(path) 將path分割成目錄和文件名二元組返回 21 os.path.dirname(path) 返回path的目錄。其實就是os.path.split(path)的第一個元素 22 os.path.basename(path) 返回path最後的文件名。若是path以/或\結尾,那麼就會返回空值。即os.path.split(path)的第二個元素 23 os.path.exists(path) 若是path存在,返回True;若是path不存在,返回False 24 os.path.isabs(path) 若是path是絕對路徑,返回True 25 os.path.isfile(path) 若是path是一個存在的文件,返回True。不然返回False 26 os.path.isdir(path) 若是path是一個存在的目錄,則返回True。不然返回False 27 os.path.join(path1[, path2[, ...]]) 根據當前操做系統的路徑分隔符將多個路徑組合後返回,第一個絕對路徑以前的參數將被忽略
print(os.path.join('c:','user','local')) # c:user\local
28 os.path.getatime(path) 返回path所指向的文件或者目錄的最後存取時間 29 os.path.getmtime(path) 返回path所指向的文件或者目錄的最後修改時間
30 os.path.getsize(path) 返回path的大小,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)是建立時間(詳細信息參見平臺的文檔)。
stat 結構

 

 

sys模塊-和python解釋器交互的模塊

1 sys.argv           命令行參數List,第一個元素是程序自己文件名
2 sys.exit(n)        退出程序,正常退出時exit(0),錯誤退出sys.exit(1)
3 sys.version        獲取Python解釋程序的版本信息
4 sys.maxint         最大的Int值
5 sys.path           返回模塊的搜索路徑,初始化時使用PYTHONPATH環境變量的值
6 sys.platform       返回操做系統平臺名稱  print(sys.platform)  #win32
7 sys.stdout.write('please:')
8 val = sys.stdin.readline()[:-1]

 

 

hashlib模塊

用於加密相關的操做,3.x裏代替了md5模塊和sha模塊,主要提供 SHA1, SHA224, SHA256, SHA384, SHA512 ,MD5 算法;

 1 import hashlib
 2  
 3 m = hashlib.md5()
 4 m.update("Hello".encode('utf8')) #python3中,內存中的字符串都是unicode類型,update參數必定須要接收bytes類型,因此須要encode轉換(由於python3中只有bytes和str兩種數據類型)
 5 m.update("It's me".encode('utf8')) 
 6 print(m.digest()) #2進制格式hash   b']\xde\xb4{/\x92Z\xd0\xbf$\x9cR\xe3Br\x8a'
 7 print(len(m.hexdigest())) #16進制格式hash 5ddeb47b2f925ad0bf249c52e342728a
 8 
 9 
10 #加密過程等同於:
11 m2 = hashlib.md5()
12 m2.update("HelloIt's me".encode('utf8')) 
13 print(len(m2.hexdigest())) #16進制格式hash 5ddeb47b2f925ad0bf249c52e342728a
14 
15 
16 
17 
18 import hashlib
19  
20 # ######## md5 ########
21  
22 hash = hashlib.md5()
23 hash.update('admin')
24 print(hash.hexdigest())
25  
26 # ######## sha1 ########
27  
28 hash = hashlib.sha1()
29 hash.update('admin')
30 print(hash.hexdigest())
31  
32 # ######## sha256 ########
33  
34 hash = hashlib.sha256()
35 hash.update('admin')
36 print(hash.hexdigest())
37  
38  
39 # ######## sha384 ########
40  
41 hash = hashlib.sha384()
42 hash.update('admin')
43 print(hash.hexdigest())
44  
45 # ######## sha512 ########
46  
47 hash = hashlib.sha512()
48 hash.update('admin')
49 print(hash.hexdigest())

 

logging模塊

1.簡單應用

 1 import logging  
 2 logging.debug('debug message')  
 3 logging.info('info message')  
 4 logging.warning('warning message')  
 5 logging.error('error message')  
 6 logging.critical('critical message')  
 
 
 
 #輸出
 WARNING:root:warning message
 ERROR:root:error message
 CRITICAL:root:critical message

 

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

 

2.靈活配置日誌級別,日誌格式,輸出位置(文件輸出和標準輸出只能選一種)

 1 import logging  
 2 logging.basicConfig(level=logging.DEBUG,  
 3                     format='%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s',  
 4                     datefmt='%a, %d %b %Y %H:%M:%S',  
 5                     filename='/tmp/test.log',  
 6                     filemode='w')  
 7   
 8 logging.debug('debug message')  
 9 logging.info('info message')  
10 logging.warning('warning message')  
11 logging.error('error message')  
12 logging.critical('critical message')
 
 
 
 #查看輸出:
 cat /tmp/test.log 
 Mon, 05 May 2014 16:29:53 test_logging.py[line:8] DEBUG debug message
 Mon, 05 May 2014 16:29:53 test_logging.py[line:9] INFO info message
 Mon, 05 May 2014 16:29:53 test_logging.py[line:10] WARNING warning message
 Mon, 05 May 2014 16:29:53 test_logging.py[line:11] ERROR error message
 Mon, 05 May 2014 16:29:53 test_logging.py[line:12] CRITICAL critical message

 

可見在logging.basicConfig()函數中可經過具體參數來更改logging模塊默認行爲,可用參數有
filename:用指定的文件名建立FiledHandler(後邊會具體講解handler的概念),這樣日誌會被存儲在指定的文件中。
filemode:文件打開方式,在指定了filename時使用這個參數,默認值爲「a」還可指定爲「w」。(a:追加寫;w:覆蓋寫)

  注意:若是沒有指定filename和filemode,默認將日誌打印到了標準輸出中。
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用戶輸出的消息

 

3.logger對象

 上述幾個例子中咱們瞭解到了logging.debug()、logging.info()、logging.warning()、logging.error()、logging.critical() 分別用以記錄不一樣級別的日誌信息;logging.basicConfig() 用默認日誌格式爲日誌系統創建一個默認的流處理器:設置基礎配置(如日誌級別等)並加到root logger中,這幾個是logging模塊級別的函數;另外還有一個模塊級別的函數是logging.getLogger([name])(返回一個logger對象,若是沒有指定名字將返回root logger)

先看一個最簡單的過程:

 1 import logging
 2 #建立一個日誌(logger)對象
 3 logger = logging.getLogger()
 4 
 5 # 建立一個handler即文件輸出流對象,用於寫入日誌文件
 6 fh = logging.FileHandler('test.log')
 7 
 8 # 再建立一個handler即標準輸出流對象,用於輸出到控制檯
 9 ch = logging.StreamHandler()
10 
11 #日誌格式對象
12 formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
13 
14 fh.setFormatter(formatter)  #爲文件輸出設置日誌格式
15 ch.setFormatter(formatter)  #爲標準輸出設置日誌格式
16 
17 #經過addHandler爲logger添加文件輸出對象和標準輸出對象
18 logger.addHandler(fh) #logger對象能夠添加多個fh和ch對象
19 logger.addHandler(ch)
20 #logger1.setLevel(logging.DEBUG)   設置輸出日誌級別,不指定默認是warnning
21 logger.debug('logger debug message')
22 logger.info('logger info message')
23 logger.warning('logger warning message')
24 logger.error('logger error message')
25 logger.critical('logger critical message')

 

輸出:

#控制檯輸出
2018-01-30 09:53:10,887 - root - WARNING - logger warning message
2018-01-30 09:53:10,887 - root - ERROR - logger error message
2018-01-30 09:53:10,887 - root - CRITICAL - logger critical message



#文件輸出
cat test.log
2018-01-30 09:53:10,887 - root - WARNING - logger warning message
2018-01-30 09:53:10,887 - root - ERROR - logger error message
2018-01-30 09:53:10,887 - root - CRITICAL - logger critical 

 

 流程圖:

 

4.應用

 1 import os
 2 import time
 3 import logging
 4 from config import settings
 5 
 6 
 7 def get_logger(card_num, struct_time):
 8 
 9     if struct_time.tm_mday < 23:
10         file_name = "%s_%s_%d" %(struct_time.tm_year, struct_time.tm_mon, 22)
11     else:
12         file_name = "%s_%s_%d" %(struct_time.tm_year, struct_time.tm_mon+1, 22)
13 
14     file_handler = logging.FileHandler(
15         os.path.join(settings.USER_DIR_FOLDER, card_num, 'record', file_name),
16         encoding='utf-8'
17     )
18     fmt = logging.Formatter(fmt="%(asctime)s :  %(message)s")
19     file_handler.setFormatter(fmt)
20 
21     logger1 = logging.Logger('user_logger', level=logging.INFO)
22     logger1.addHandler(file_handler)
23     return logger1
View Code

 

 

ConfigParser模塊

經常使用配置文件的格式以下:

 1 [DEFAULT]
 2 ServerAliveInterval = 45
 3 Compression = yes
 4 CompressionLevel = 9
 5 ForwardX11 = yes
 6   
 7 [bitbucket.org]
 8 User = hg
 9   
10 [topsecret.server.com]
11 Port = 50022
12 ForwardX11 = no

使用python生成一個這樣的文檔:

 1 import configparser
 2 
 3 config = configparser.ConfigParser()   #生成一個文件操做句柄
 4 config["DEFAULT"] = {'ServerAliveInterval': '45',
 5                      'Compression': 'yes',
 6                      'CompressionLevel': '9'}
 7 
 8 config['bitbucket.org'] = {}
 9 config['bitbucket.org']['User'] = 'hg'
10 config['topsecret.server.com'] = {}
11 topsecret = config['topsecret.server.com']
12 topsecret['Host Port'] = '50022'  # mutates the parser
13 topsecret['ForwardX11'] = 'no'  # same here
14 config['DEFAULT']['ForwardX11'] = 'yes'
15 with open('example.ini', 'w') as configfile:   #建立文件
16     config.write(configfile)

 

 

增刪改查操做:

 1 import configparser
 2 
 3 config = configparser.ConfigParser()
 4 #---------------------------------------------查
 5 print(config.sections())   #[]
 6 config.read('example.ini')   #關聯文件
 7 print(config.sections())    #['bitbucket.org', 'topsecret.server.com'] 即打印字段,default是默認字段,不會顯示出來
 8 print(config.defaults())    #OrderedDict([('compression', 'yes'), ('compressionlevel', '9'), ('serveraliveinterval', '45'), ('forwardx11', 'yes')]) 查看default字段下的全部屬性以及屬性值
 9 print(config.items('bitbucket.org'))  #[('serveraliveinterval', '45'), ('compression', 'yes'), ('compressionlevel', '9'), ('forwardx11', 'yes'), ('user', 'hg')] 查看非default字段下的全部屬性以及屬性值
10 print(config.options('bitbucket.org'))#['user', 'serveraliveinterval', 'compression', 'compressionlevel', 'forwardx11'] 查看字段下的屬性
11 print('bytebong.com' in config)# False   查看配置文件中是否有該字段
12 print(config.has_section('bitbucket.org'))  #查看配置文件中是否有該字段
13 print(config['bitbucket.org']['User']) # hg   查看屬性值
14 
15 for key in config:
16     print(key)
17 # 輸出:打印config下的全部字段
18 # DEFAULT
19 # bitbucket.org
20 # topsecret.server.com
21 
22 
23 for key in config['bitbucket.org']:
24     print(key)
25 # 輸出:bitbucket.org字段下的屬性以及default字段下的屬性
26 # user
27 # compression
28 # compressionlevel
29 # serveraliveinterval
30 # forwardx11
31 
32 #---------------------------------------------刪,改,增
33 
34 #刪除字段
35 config.remove_section('topsecret.server.com')
36 
37 #添加字段
38 config.add_section('yuan')
39 
40 #修改屬性值
41 config.set('bitbucket.org','user','lriwu')
42 
43 #刪除鍵值對
44 config.remove_option('bitbucket.org','user')
45 
46 
47 (config.write(open('r.cfg', "w")))  #最後這句語句是必須的

 

 

re模塊

正則表達式是一種小型的、高度專業化的編程語言,它內嵌在Python中,經過 re 模塊實現。正則表達式模塊被編譯成一系列的字節碼,而後由C 編寫的匹配引擎執行。

做用:字符串提供的方法是徹底匹配,沒法實現模糊匹配,因此引入正則的緣由是能夠實現模糊匹配。

實現判斷手機號碼格式:

phone_number = input('please input your phone number : ')

while True:
    phone_number = input('please input your phone number : ')
    if len(phone_number) == 11 \
            and phone_number.isdigit()\
            and (phone_number.startswith('13') \
            or phone_number.startswith('14') \
            or phone_number.startswith('15') \
            or phone_number.startswith('18')):
        print('是合法的手機號碼')
    else:
        print('不是合法的手機號碼')

經過re模塊:

import re
phone_number = input('please input your phone number : ')
if re.match('^(13|14|15|18)[0-9]{9}$',phone_number):
        print('是合法的手機號碼')
else:
        print('不是合法的手機號碼')

對比上面的兩種寫法,使用正則表達式會簡便很是多。

正則表達式

正則表達式自己和python沒有什麼關係,就是匹配字符串內容的一種規則。

字符組:[]

在同一個位置可能出現的各類字符組成了一個字符組,在正則表達式中用[]表示
字符分爲不少類,好比數字、字母、標點等等。
假如你如今要求一個位置"只能出現一個數字",那麼這個位置上的字符只能是0、一、2...9這10個數之一。

單字符:

量詞:

. ^ $

 

* + ? { }

注意:前面的*,+,?等都是貪婪匹配,也就是儘量匹配,後面加?號使其變成惰性匹配

字符集[][^]

分組 ()與 或 |[^]

身份證號碼是一個長度爲15或18個字符的字符串,若是是15位則所有🈶️數字組成,首位不能爲0;若是是18位,則前17位所有是數字,末位多是數字或x,下面咱們嘗試用正則來表示:

轉義符 \

在正則表達式中,有不少有特殊意義的是元字符,好比\n和\s等,若是要在正則中匹配正常的"\n"而不是"換行符"就須要對"\"進行轉義,變成'\\'。

在python中,不管是正則表達式,仍是待匹配的內容,都是以字符串的形式出現的,在字符串中\也有特殊的含義,自己還須要轉義。因此若是匹配一次"\n",字符串中要寫成'\\n',那麼正則裏就要寫成"\\\\n",這樣就太麻煩了。這個時候咱們就用到了r'\n'這個概念,此時的正則是r'\\n'就能夠了。( r的做用是取消‘\’的轉義功能)

如今咱們聊一聊\,先看下面兩個匹配:

 1 #-----------------------------eg1:  2 import re  3 ret=re.findall('c\l','abc\le')  4 print(ret)#[] 沒有匹配  5 ret=re.findall('c\\l','abc\le')  6 print(ret)#[] 沒有匹配  7 ret=re.findall('c\\\\l','abc\le') #在python解釋器裏先將‘\\\\’轉義成‘\\’;再在re模塊裏將'\\'轉義成‘\’ ,即就匹配到了‘c\l’  8 print(ret)#['c\\l'] 匹配到了  9 ret=re.findall(r'c\\l','abc\le') #r表示告訴python解釋器裏面的字符串就是原生字符串,在python接收器中無需轉義 10 print(ret)#['c\\l'] 匹配到了 11 12 #-----------------------------eg2: 13 #之因此選擇\b是由於\b在ASCII表中是有意義的 14 m = re.findall('\bblow', 'blow') 15 print(m) #[] 沒有匹配 16 m = re.findall(r'\bblow', 'blow') 17 print(m) #['blow'] 匹配到了

 

  

貪婪匹配

貪婪匹配:在知足匹配時,匹配儘量長的字符串,默認狀況下,採用貪婪匹配。

.*:儘量取屢次

幾個經常使用的非貪婪匹配Pattern:

.*? 儘量取少次

*? 重複任意次,但儘量少重複
+? 重複1次或更屢次,但儘量少重複
?? 重複0次或1次,但儘量少重複
{n,m}? 重複n到m次,但儘量少重複
{n,}? 重複n次以上,但儘量少重複

.*?的用法

. 是任意字符
* 是取 0 至 無限長度
? 是非貪婪模式。
合在一塊兒就是 取儘可能少的任意字符,通常不會這麼單獨寫,他大多用在:
.*?x

就是取前面任意長度的字符,直到一個x出現

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字符串能夠是多行的,忽略空白字符,並能夠添加註釋

 

re模塊

字符匹配(普通字符,元字符):

1.普通字符:字符串提供的方法是徹底匹配,沒法實現模糊匹配。

1 import re
2 re.findall('w\w{2}l', 'hello world')  #['worl']  模糊匹配
3 re.findall('alex','yuanaleSxalexwupeiqi') #['alex'] 精確匹配(若是隻實現這一功能,使用字符串的方法就能夠了)

 

2.元字符:能夠實現模糊匹配

  • 元字符之. ^ $ * + ? { }
 1 import re
 2 
 3 #'.':匹配任意字符一次(不能匹配換行符)
 4 ret = re.findall('a..in', 'helloalvin')
 5 print(ret)  # ['alvin']
 6 
 7 #'^':行首匹配
 8 ret = re.findall('^a...n', 'alvinhelloawwwn')
 9 print(ret)  # ['alvin']
10 
11 #'$':行尾匹配
12 ret = re.findall('a...n$', 'alvinhelloawwwn')
13 print(ret)  # ['awwwn']
14 
15 #'*':即匹配前面的字符[0,+oo]次
16 ret = re.findall('abc*', 'abcccc')
17 print(ret)  # ['abcccc']   #貪婪匹配
18 ret = re.findall('abc*', 'ab')
19 print(ret)  # ['ab']   #匹配0次例子
20 
21 #'+':匹配前面的字符[1,+oo]次即匹配前面的字符至少一次
22 ret = re.findall('abc+', 'abccc')
23 print(ret)  # ['abccc']  #貪婪匹配
24 
25 #'?':匹配前面的字符[0,1]次
26 ret=re.findall('abc?','abccc')#[0,1]
27 print(ret)#['abc']  #貪婪匹配
28 ret = re.findall('a?b', 'aaaabhghabfb')
29 print(ret)  # ['ab','ab','b']
30 
31 
32 ret = re.findall('abc{1,4}', 'abccc')  #匹配前面的1-4次都行
33 print(ret)  # ['abccc']  貪婪匹配
34 ret = re.findall('a{5}b','aaaaab')  #aaaaab  匹配前面的5次

注意:前面的*,+,?等都是貪婪匹配,也就是儘量屢次匹配,後面加?號使其變成惰性匹配即按照最少的進行匹配;

1 ret=re.findall('abc*?','abcccccc')
2 print(ret)#['ab']

 

  • 元字符之字符集[]:
 1 # --------------------------------------------字符集[]
 2 ret = re.findall('a[bc]d', 'acd')   #或的關係[b,c]表示b或c
 3 print(ret)  # ['acd']
 4 
 5 ret = re.findall('[a-z]', 'acd')
 6 print(ret)  # ['a', 'c', 'd']
 7 
 8 #取消元字符的特殊功能
 9 ret = re.findall('[.*+]', 'a.cd+')  #這裏的.*+只表示自身意義
10 print(ret)  # ['.', '+']
11 
12 # 在字符集裏仍有功能的符號: - ^ \
13 ret = re.findall('[1-9]', '45dha3')     #'-'表明範圍
14 print(ret)  # ['4', '5', '3']
15 
16 ret = re.findall('[^a,b]', '45bdha3')    #'^'表明取反即除了a和b之外的
17 #等同於:ret = re.findall('[^ab]', '45bdha3')
18 print(ret)  # ['4', '5', 'd', 'h', '3']
19 
20 
21 # 反斜槓後邊跟元字符去除特殊功能,好比\.
22 # 反斜槓後邊跟普通字符實現特殊功能,好比\d,至關於類 [0-9]
23 ret = re.findall('[\d]', '45bdha3')
24 print(ret)  # ['4', '5', '3']

反斜槓後邊跟元字符去除特殊功能,好比\.

反斜槓後邊跟普通字符實現特殊功能,好比\d

\d  匹配任何十進制數;它至關於類 [0-9]。
\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_]
\b  匹配一個特殊字符邊界,好比空格 ,&,#,$等

1 ret=re.findall('I\b','I am LIST')
2 print(ret)#[]   
3 ret=re.findall(r'I\b','I am LI$T')
4 print(ret)#['I','I']

 

  • 元字符之分組()
1 print(re.search('(as)+','sdjkfasas').group())   #asas    '+' 匹配前面分組[1,+oo]次
2 ret = re.findall('www.(\w+).com','www.baidu.com') #['baidu'] 只會打印出組中的內容,分組是有優先的
3  ret = re.findall('www.(?:\w+).com','www.baidu.com') #['www.baidu.com'] 取消組的權限

 

1 ret=re.search('(?P<id>\d{2})','23/com')  #?P<id> 爲分組取名字爲id
2 print(ret.group())#23
3 print(ret.group('id'))#23  #經過分組名取匹配到的值

 注意:

1 findall的優先級查詢:

import re ret = re.findall('www.(baidu|oldboy).com', 'www.oldboy.com') print(ret) # ['oldboy'] 這是由於findall會優先把匹配結果組裏內容返回,若是想要匹配結果,取消權限便可  ret = re.findall('www.(?:baidu|oldboy).com', 'www.oldboy.com') print(ret) # ['www.oldboy.com']

2 split的優先級查詢

ret=re.split("\d+","eva3egon4yuan") print(ret) #結果 : ['eva', 'egon', 'yuan']  ret=re.split("(\d+)","eva3egon4yuan") print(ret) #結果 : ['eva', '3', 'egon', '4', 'yuan'] #在匹配部分加上()以後所切出的結果是不一樣的, #沒有()的沒有保留所匹配的項,可是有()的卻可以保留了匹配的項, #這個在某些須要保留匹配部分的使用過程是很是重要的。

 

  • 元字符之或 | :或從左至右邊匹配,只要匹配上就不繼續匹配了,因此應該把長的放前面
ret=re.search('(?P<id>\d{2})/(?P<name>\w{3})','23/com')
 print (ret.group()) #23/com     
 print (ret.group( 'id' )) #23

 

  • re模塊下的經常使用方法
 1 import re
 2 
 3 # 1
 4 re.findall('a', 'alvin yuan')  # ['a', 'a']即返回全部知足匹配條件的結果,放在列表裏
 5 # 2
 6 ret = re.search('a', 'alvin yuan')  
7 print(ret) # <_sre.SRE_Match object; span=(0, 1), match='a'> 找整個字符串,遇到匹配的就返回,即返回匹配到的第一個對象,該對象能夠調用group()返回結果;若是字符串沒有匹配,則返回None,此時調用group()方法會報錯。
8 print(ret.group()) # 'a'
ret = re.search('a', 'alvin yuan')
if ret:
print(ret.group())
8 # 3 9 re.match('a', 'abca').group() # 'a' 同search,不過只在字符串開始處進行匹配 10 re.match('a', 'df asbca as').group()  # 報錯
11 # 4 分割 12 ret = re.split('b', 'abcd') 13 print(ret) # ['a', 'cd'] 14 15 ret = re.split('[ab]', 'abcd') # 先按'a'分割獲得''和'bcd',在對''和'bcd'分別按'b'分割 16 print(ret) # ['', '', 'cd'] 17 18 ret = re.split('[js]', 'sdjksal') #['', 'd', 'k', 'al'] 19 20 # 5 替換 21 ret = re.sub('\d', 'abc', 'alvin5yuan6', 1) 22 print(ret) # alvinabcyuan6 23 ret = re.subn('\d', 'abc', 'alvin5yuan6') #沒有指定第三個參數,所有替換 24 print(ret) # ('alvinabcyuanabc', 2) 25 26 # 6 compile能夠把正則表達式編譯成一個正則表達式對象,能夠把常用的正則表達式編譯成正則表達式對象,這樣能夠提升必定的效率。 27 obj = re.compile('\d{3}') #實現一種規則能夠匹配屢次 28 ret = obj.search('abc123eeee') 29 print(ret.group()) # 123
30
31 #7
32 ret = re.finditer('\d','ds3sy4784a')
33 print(res) #<callable_iterator object at 0x00000233DBFA5208> 返回一個存放匹配結果的迭代器對象
34 print(next(ret).group()) #3 查看第一個結果
35 print(next(ret).group())  #4   查看第二個結果

練習

import re


ret = re.search("<(?P<tag_name>\w+)>\w+</(?P=tag_name)>","<h1>hello</h1>")
#還能夠在分組中利用?p<name>的形式給分組起名字,?P=tag_name:引用前面分組標籤的名字
#獲取的匹配結果能夠直接用group('名字')拿到對應的值
print(ret.group('tag_name'))  #結果 :h1
print(ret.group())  #結果 :<h1>hello</h1>

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', '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']


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

二、 匹配一段文本中的每行的時間字符串,好比:‘1990-07-12’;

   分別取出1年的12個月(^(0?[1-9]|1[0-2])$)、
   一個月的31天:^((0?[1-9])|((1|2)[0-9])|30|31)$

三、 匹配qq號。(騰訊QQ號從10000開始)  [1,9][0,9]{4,}

四、 匹配一個浮點數。       ^(-?\d+)(\.\d+)?$   或者  -?\d+\.?\d*

五、 匹配漢字。             ^[\u4e00-\u9fa5]{0,}$ 

六、 匹配出全部整數
匹配數字

 

json模塊、pickle模塊、shelve模塊--序列化的模塊

引入:沒法將字典直接寫入文件,須要經過eval()方法,不過,eval方法是有侷限性的。對於普通的數據類型,json.loads和eval都能用,但遇到特殊類型的時候,eval就無論用了,因此eval的重點仍是一般用來執行一個字符串表達式,並返回表達式的值。

 1 # 字典沒法直接寫入文件
 2 #dic = {'1':'111'}
 3 #f = open('test','w')
 4 #f.write(dic)  #報錯 TypeError: write() argument must be str, not dict
 5 
 6 #須要將字典轉化成字符串才能寫入文件
 7 dic = {'1':'111'}
 8 str1 = str(dic)
 9 f = open('test','w')
10 f.write(str1)    #{'1': '111'} 成功寫入文件
11 
12 #讀取文件內容
13 # f = open('test','r')
14 # data = f.read()
15 # print(data['1'])   #在文件中保存的是字符串而不是字典,因此這種方式取值將會報錯
16 
17 #經過eval轉換成字典類型再取值
18 f = open('test','r')
19 data = f.read()
20 print(eval(data)['1'])  #111

序列化:

咱們把對象(變量)從內存中變成可存儲或傳輸的過程稱之爲序列化即將數據類型轉化成字符串的過程

序列化以後,就能夠把序列化後的內容寫入磁盤,或者經過網絡傳輸到別的機器上。

反過來,把變量內容從序列化的對象從新讀到內存裏稱之爲反序列化即將字符串轉化成數據類型的過程

三種模塊的區別:

若是咱們要在不一樣的編程語言之間傳遞對象,就必須把對象序列化爲標準格式,好比XML,但更好的方法是序列化爲JSON,由於JSON表示出來就是一個字符串,能夠被全部語言讀取,能夠方便地存儲到磁盤或者經過網絡傳輸。JSON不只是標準格式,而且比XML更快,並且能夠直接在Web頁面中讀取,很是方便。可是JSON也存在缺點:只有不多的一部分數據類型可以經過json轉化成字符串。因而就有了pickle。

pickle:python中全部的數據類型均可以轉化成字符串形式;可是pickle序列化的內容只有python能理解且部分反序列化依賴代碼。

shelve:shelve模塊比pickle模塊簡單,shelve只提供一個open方法,返回相似字典的對象,可讀可寫。key必須爲字符串,而值能夠是python所支持的數據類型。

在如下兩種狀況下才會使用到序列化

1.數據存儲

2.網絡傳輸

json:json是通用的序列化格式,可以作到不一樣語言之間的轉換

JSON表示的對象就是標準的JavaScript語言的對象,JSON和Python內置的數據類型對應以下:

序列化方法:dumps,直接對內存中的對象進行序列化操做,操做完成後對象依然在內存中存在

import json
dic={'name':'lriwu','age':'18'}
print(type(dic),dic)
data=json.dumps(dic)
print(type(data),data)
f=open('json_test','w')
f.write(data)
f.close()

# <class 'dict'> {'name': 'lriwu', 'age': '18'}
# <class 'str'> {"name": "lriwu", "age": "18"}

#文件中保存的內容:
#{"name": "lriwu", "age": "18"}   即以json對應的字典格式進行存儲(json中對應的字典類型是{})

反序列化方法:loads,直接對內存中的對象進行序列化操做,操做完成後對象依然在內存中存在

1 import json
2 f=open('json_test','r')
3 # data=f.read()
4 # print(data) # {"age": "18", "name": "lriwu"}
5 # data['name'] #dumps序列化的沒法直接取值,須要經過loads方法進行反序列化 6 data=f.read() 7 data=json.loads(data) 8 print(data['name']) #lriwu

 json能夠對普通的數據類型轉化成json的字符串;可是不能將高級的對象(函數或類)轉化成json的字符串。

1 import json
2 
3 def foo():
4     print('ok')
5 
6 data=json.dumps(foo)  #TypeError: <function foo at 0x00000225799AC620> is not JSON serializable 函數不是json的序列化類型

json將普通的數據類型轉化成json的字符串,只能是:數字、字符串、列表、字典、元組;可是不能將高級的對象(函數或類)轉化成json的字符串,若是須要將這些高級的對象轉化成jison的字符串,可使用pickle。 

 

序列化方法:dump,向文件中寫入。如下述爲例:先將字典進行序列化操做成字符串後寫入文件

import json
dic = {1:"a",2:'b'}
f = open('fff','w',encoding='utf-8')
json.dump(dic,f)
f.close()

# 文件中的內容
# {」1":"a","2":"b"}

反序列化方法:load,讀文件中內容

import json
f = open('fff',encoding='utf-8')
ret = json.load(f)
f.close()
print(type(ret),ret)


# <class 'dict'> {'1':'a','2':'b'}

注意:dump(s)能夠屢次寫入文件,當屢次寫入時,使用load(s)一次性讀出來會報錯即出現只能寫沒法讀的現象;因此json只能在dump(s)一次性寫入後,然後使用load(s)一次性讀出。這又會產生另一個問題:當寫入文件的內容過大時,一次性讀出很是佔用內存。解決以下例子(使用loads和dumps):

# 分次寫入文件
l = [{'k':'111'},{'k2':'111'},{'k3':'111'}]
f = open('file','w')
import json
for dic in l:
    str_dic = json.dumps(dic)
    f.write(str_dic+'\n')
f.close()


# file文件中內容以下:
{"k":"111"}
{"k2":"111"}
{"k3":"111"}



# 分次讀文件內容
f = open('file')
import json
l = []
for line in f:
    dic = json.loads(line.strip())
    l.append(dic)
f.close()
print(l)

 # [{'k':'111'},{'k2':'111'},{'k3':'111'}]

 

pickle

序列化:dumps

 1 import pickle
 2 
 3 def foo():
 4     print('ok')
 5 
 6 data=pickle.dumps(foo)
 7 f=open('pickle_test','wb')  #pickle dumps時必須是以bytes數據類型寫入,字符串類型沒法寫入;'wb':表示把寫入文件的內容轉化爲bytes以後再寫入文件;‘w’:默認寫入的是str的數據類型(loads時也必須以bytes方式讀)
 8 f.write(data)  
 9 f.close()
10 
11 #f=open('pickle_test','w') 將會報錯TypeError: write() argument must be str, not bytes

 反序列化:loads

1 import pickle
2 def foo():
3     print('ok')
4 f=open('pickle_test','rb')
5 data=f.read()
6 data=pickle.loads(data)
7 data()  #調用data就至關於執行了foo()函數,前提是當前腳本也須要定義foo()函數即load和dumps兩個文件都必需要有foo()函數

dump和load方法:

1 import json
2 dic = {'name':'lriwu','age':'18'}
3 f = open('JSON_test','w')
4 # data = json.dumps(dic)
5 # f.write(data)
6 json.dump(dic,f) #這句話等同於data = json.dumps(dic)和f.write(data)這兩句即f.write(data)省略了
7 f.close()

 

1 import json
2 f=open('JSON_test','r')
3 # data=f.read()
4 # data=json.loads(data)
5 data = json.load(f)  #少了f.read()
6 print(data['name'])   #lriwu

注意:pickle能夠實現分步寫入,分步讀出

import time
struct_time1  = time.localtime(1000000000)
struct_time2  = time.localtime(2000000000)
f = open('pickle_file','wb')
pickle.dump(struct_time1,f)   # 分步寫入1
pickle.dump(struct_time2,f)   # 分步寫入2
f.close()
f = open('pickle_file','rb')
struct_time1 = pickle.load(f)  # 分步讀出1
struct_time2 = pickle.load(f)  # 分步讀出2
print(struct_time1.tm_year)
print(struct_time2.tm_year)
f.close()

 

shelve模塊

使用句柄直接操做數據類型。

存數據:

1 import shelve
2 f = shelve.open('shelve.txt')  #獲得一個文件句柄
3  
4 f['stu1_info']={'name':'alex','age':'18'}   #後續還能繼續添加其它字典,很是靈活
5 #print(f['stu1_info']) {'name':'alex','age':'18'}
7 #print(f['stu1_info']['age']) #18
8 #print(f.get('stu1_info')['age']) #18 取字典中的內容(本地取)

 取數據:(在另一個文件中取上述存的數據)

import shelve
 
f = shelve.open('shelve.txt')

data = f.get('stu1_info')['age']
print(data)   #18

get方法:

 1 d = {'name':'lriwu','age':'18'}
 2 #取鍵值,方法一:
 3 print(d['name'])  #lriwu
 4 #print(d.['sex'])  #無該鍵將會報錯
 5 
 6 
 7 #取鍵值,方法二:
 8 print(d.get('name')) #lriwu
 9 print(d.get('sex')) #None 無該鍵將會返回None
10 print(d.get('sex','male'))  #male 該鍵將會返回自定義的值

shelve模塊有個限制,不支持多個應用同一時間往同一個DB進行寫操做。因此當咱們知道應用若是隻進行讀操做,咱們可讓shelve經過只讀方式打開DB。

import shelve
f = shelve.open('shelve_file')
f['key'] = {'int':10, 'float':9.5, 'string':'Sample data'}  #直接對文件句柄操做,就能夠存入數據
f.close()

f1 = shelve.open('shelve_file')
existing = f1['key']  #取出數據的時候也只須要直接用key獲取便可,可是若是key不存在會報錯
f1.close()
print(existing)

# 只讀方式:flag=r
f = shelve.open('shelve_file', flag='r')
existing = f['key']
f.close()
print(existing)
只讀方式:flag=r

因爲shelve在默認狀況下是不會記錄待持久化對象的任何修改的,因此咱們在shelve.open()時須要修改默認參數,不然對象的修改不會保存。

import shelve
f = shelve.open('shelve_file')
f['key'] = {'int':10, 'float':9.5, 'string':'Sample data'}  #直接對文件句柄操做,就能夠存入數據
f.close()


f1 = shelve.open('shelve_file')
print(f1['key'])  # {'string': 'Sample data', 'float': 9.5, 'int': 10}
f1['key']['new_value'] = 'this was not here before'
f1.close()

f2 = shelve.open('shelve_file')
print(f2['key'])  # {'float': 9.5, 'string': 'Sample data', 'int': 10}  現象是文件未被修改

# writeback=True
f2 = shelve.open('shelve_file', writeback=True)
print(f2['key'])  # {'float': 9.5, 'string': 'Sample data', 'int': 10}
f2['key']['new_value'] = 'this was not here before'
print(f2['key'])   # {'new_value': 'this was not here before', 'int': 10, 'string': 'Sample data', 'float': 9.5}
f2.close()
writeback=True

 

xml模塊

xml是實現不一樣語言或程序之間進行數據交換的協議,跟json差很少,但json使用起來更簡單,不過,古時候,在json還沒誕生的黑暗年代,你們只能選擇用xml呀,至今不少傳統公司如金融行業的不少系統的接口還主要是xml。

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

 1 <?xml version="1.0"?>
 2 <data>
 3     <country name="Liechtenstein">
 4         <rank updated="yes">2</rank>
 5         <year>2008</year>
 6         <gdppc>141100</gdppc>
 7         <neighbor name="Austria" direction="E"/>
 8         <neighbor name="Switzerland" direction="W"/>
 9     </country>
10     <country name="Singapore">
11         <rank updated="yes">5</rank>
12         <year>2011</year>
13         <gdppc>59900</gdppc>
14         <neighbor name="Malaysia" direction="N"/>
15     </country>
16     <country name="Panama">
17         <rank updated="yes">69</rank>
18         <year>2011</year>
19         <gdppc>13600</gdppc>
20         <neighbor name="Costa Rica" direction="W"/>
21         <neighbor name="Colombia" direction="E"/>
22     </country>
23 </data>

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

 1 import xml.etree.ElementTree as ET
 2 
 3 tree = ET.parse("xmltest.xml")    #xmltest.xml 文件名,獲得一個xml對象
 4 root = tree.getroot()
 5 print(root.tag)     #data 即獲得最外層的標籤名字
 6 
 7 # 遍歷xml文檔
 8 for child in root:
 9     print(child.tag, child.attrib)  #獲得 country {'name':'Liechtenstein'}  country {'name':'Singapore'}   country {'name':'Panama'}
10     for i in child:
11         print(i.tag, i.text)
12 
13 # 只遍歷year 節點
14 for node in root.iter('year'):
15     print(node.tag, node.text)
16 # ---------------------------------------
17 
18 import xml.etree.ElementTree as ET
19 
20 tree = ET.parse("xmltest.xml")
21 root = tree.getroot()
22 
23 # 修改
24 for node in root.iter('year'):
25     new_year = int(node.text) + 1  #年份加1
26     node.text = str(new_year)
27     node.set("updated", "yes")    #新加一個屬性   <year> upadta='yes'>2009</year>  <year> upadta='yes'>2012</year>  <year> upadta='yes'>2012</year>
28 
29 
30 tree.write("xmltest.xml")
31 
32 # 刪除node
33 for country in root.findall('country'):
34     rank = int(country.find('rank').text)
35     if rank > 50:
36         root.remove(country)
37 
38 tree.write('output.xml')

本身建立xml文檔:

 1 import xml.etree.ElementTree as ET
 2  
 3  
 4 new_xml = ET.Element("namelist")
 5 name = ET.SubElement(new_xml,"name",attrib={"enrolled":"yes"})
 6 age = ET.SubElement(name,"age",attrib={"checked":"no"})
 7 sex = ET.SubElement(name,"sex")
 8 sex.text = '33'
 9 name2 = ET.SubElement(new_xml,"name",attrib={"enrolled":"no"})
10 age = ET.SubElement(name2,"age")
11 age.text = '19'
12  
13 et = ET.ElementTree(new_xml) #生成文檔對象
14 et.write("test.xml", encoding="utf-8",xml_declaration=True)
15  
16 ET.dump(new_xml) #打印生成的格式

 

 

subprocess模塊

import subprocess
################subprocess 案例1
# a= subprocess.Popen('dir', shell=True)  #實例化一個對象,並將命令執行結果輸出在屏幕;這裏的subprocess本身開了一個子進程,執行結果由該子進程輸出至屏幕,這個子進程和主進程無關;subprocess.Popen('dir', shell=True)和print(a)誰先輸出取決於誰的執行速度快
# print(a)

# 輸出
# <subprocess.Popen object at 0x000001C1386E2978>
# 2018/03/08  15:34    <DIR>          .
# 2018/03/08  15:34    <DIR>          ..
# 2018/03/08  11:24               357 client.py
# 2018/03/08  15:33             1,014 server.py
# 2018/03/08  15:34               370 subpro.py
# 2018/03/08  15:31    <DIR>          __pycache__

################subprocess 案例2
# a=subprocess.Popen('dir',shell=True,stdout=subprocess.PIPE) #實例化一個對象,命令執行結果不會在屏幕輸出,該執行結果保存在subprocess的子進程中;stdout=subprocess.PIPE就是將執行結果經過管道從子進程保存到主進程上,以便經過方法能夠獲取到執行結果
# print(a)  #獲取執行的結果

#輸出:<subprocess.Popen object at 0x000001C77CCA2978>
#這時候執行結果就不會在屏幕上輸出了

################subprocess 案例2 經過方法調用執行結果
# a=subprocess.Popen('dir',shell=True,stdout=subprocess.PIPE)
# #print(a.stdout.read())      #輸出的是bytes類型 b' \xc7\xfd\xb6\xaf\xc6\xf7 F \xd6\xd0\xb5\xc4\xbe\xed\xca\xc7 studying\r\n \xbe\xed\xb5\xc4\xd0\xf2\xc1\xd0\xba\xc5\xca\xc7 0006-6FF7\r\n\r\n F:\\code\\day26 \xb5\xc4\xc4\xbf\xc2\xbc\r\n\r\n2018/03/08  15:56    <DIR>          .\r\n2018/03/08  15:56    <DIR>          ..\r\n2018/03/08  11:24               357 client.py\r\n2018/03/08  15:33             1,014 server.py\r\n2018/03/08  15:56             1,454 subpro.py\r\n2018/03/08  15:31    <DIR>          __pycache__\r\n               3 \xb8\xf6\xce\xc4\xbc\xfe          2,825 \xd7\xd6\xbd\xda\r\n               3 \xb8\xf6\xc4\xbf\xc2\xbc 81,451,225,088 \xbf\xc9\xd3\xc3\xd7\xd6\xbd\xda\r\n'
# print(str(a.stdout.read(),'gbk'))

# 輸出:
# 2018/03/08  16:01    <DIR>          .
# 2018/03/08  16:01    <DIR>          ..
# 2018/03/08  11:24               357 client.py
# 2018/03/08  15:33             1,014 server.py
# 2018/03/08  16:01             2,132 subpro.py
# 2018/03/08  15:31    <DIR>          __pycache__
#                3 個文件          3,503 字節
#                3 個目錄 81,451,225,088 可用字節
View Code

 

collections模塊-python中的擴展數據類型

在內置數據類型(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)
print(p.x)   # 1
print(p.y)   # 2
print(p) # point(x=1,y=2)

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

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

deque

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

# 隊列:先進先出
import queue
q = queue.Queue
q.put(10)
q.put(5)
q.put(6)
print(q.get())  # 10
print(q.get())  #  5
print(q.get())  #  6
print(q.get())  #  不報錯,程序處於阻塞狀態,直到向隊列中再放值時,從阻塞狀態釋放


#雙端隊列:deque
#deque是爲了高效實現插入和刪除操做的雙向列表,適合用於隊列和棧
from collections import deque
q = deque(['a', 'b', 'c'])
q.append('x')      #向隊列後面放數據
q.appendleft('y') #向隊列前面放數據
print(q)   # deque(['y', 'a', 'b', 'c', 'x'])

# deque.pop()   #向隊列後面取數據
# deque.popleft #向隊列前面取數據
# deque.insert(1,3)  #插隊

OrderedDict

使用dict時,Key是無序的。在對dict作迭代時,咱們沒法肯定Key的順序。若是要保持Key的順序,能夠用OrderedDict

from collections import OrderedDict
d = dict([('a', 1), ('b', 2), ('c', 3)])
print(d) # dict的Key是無序的   {'a': 1, 'c': 3, 'b': 2}
od = OrderedDict([('a', 1), ('b', 2), ('c', 3)])
print(od)  # OrderedDict的Key是有序的  OrderedDict([('a', 1), ('b', 2), ('c', 3)])


od = OrderedDict()
od['z'] = 1
od['y'] = 2
od['x'] = 3  # 按照插入的Key的順序返回
# ['z', 'y', 'x']

defaultDict

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

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
#d = defaultdict(list)  #字典的默認值爲列表,括號中必須爲可調用對象
#print(d['k'])   # []


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)
print(my_dict)
# defaultdict(<class 'list'>, {'k1': [77, 88, 99, 90], 'k2': [11, 22, 33, 44, 55, 66]})
defaultdict字典解決方法

使用dict時,若是引用的Key不存在,就會拋出KeyError。若是但願key不存在時,返回一個默認值,就能夠用defaultdict:
即: {'k1': 大於66 , 'k2': 小於66}

>>> 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})
相關文章
相關標籤/搜索