collections模塊php
時間模塊html
random模塊node
os模塊python
sys模塊nginx
序列化模塊算法
re模塊shell
hashlib模塊數據庫
hmac模塊json
configparse模塊安全
logging模塊
常見的場景:一個模塊就是一個包含了python定義和聲明的文件,文件名就是模塊名字加上.py的後綴;
使用import加載的模塊分爲四個通用類別:
a.使用python編寫的代碼(.py文件) b.已被編譯爲共享庫或dll的C或C++擴展
c.包好一組模塊的包 d.使用C編寫並連接到python解釋器的內置模塊
使用模塊的好處:
若是咱們退出python解釋器而後從新進入,那麼以前定義的函數或是變量都將丟失,所以咱們一般將程序寫到文件中以便永久保存下來,須要時就經過命令行方式去運行,此時*.py就被稱做腳本script。
隨着程序的發展,功能愈來愈多,爲了方便管理,咱們一般將程序分紅一個個的文件,這樣作程序的結果更清晰,方便管理,這時咱們不只僅能夠把這些文件當作腳本去執行,還能夠把它們當作模塊來導入到其餘的模塊中,實現功能的重複利用。
模塊的導入應在程序開始的地方;
http://www.cnblogs.com/Eva-J/articles/7292109.html此處先放置一個連接;
說明:顧名思義,時間模塊就是用來解決一些和時間相關的問題,在使用時間模塊前,咱們應該先將此模塊導入到命名空間中;
名稱:time
表示時間的三種方式:
1)時間戳時間(timestamp)
說明:時間戳指的是從1970年1月1號的00:00:00開始按秒計算的偏移量;
類型:浮點型;
查看:time.time() #表示當前的時間戳;
>>> import time #導入time模塊 >>> time.time() #查看當前時間戳 1534750110.050263 >>> print(type(time.time())) 查看時間戳的數據類型 <class 'float'>
2)格式化時間(Format String)
說明:將當前的時間進行格式化輸出一方便用戶閱讀效果;
類型:字符串;
查看:time.strftime(n) #表示以格式化方式輸出時間;
參數:n ------> 表示自定義輸出格式,好比:「%Y-%m-%d」、「%Y/%m/%d %H:%M:%S」等等之類的
>>> import time #導入time模塊 >>> time.strftime("%Y-%m-%d %H:%M:%S") #根據定義格式進行輸出 '2018-08-20 15:33:47' >>> print(type(time.strftime("%Y-%m-%d %H:%M:%S"))) #查看格式化時間的類型 <class 'str'>
%y 兩位數的年份表示(00-99) %Y 四位數的年份表示(000-9999) %m 月份(01-12) %d 月內中的一天(0-31) %H 24小時制小時數(0-23) %I 12小時制小時數(01-12) %M 分鐘數(00=59) %S 秒(00-59) %a 本地簡化星期名稱 %A 本地完整星期名稱 %b 本地簡化的月份名稱 %B 本地完整的月份名稱 %c 本地相應的日期表示和時間表示 %j 年內的一天(001-366) %p 本地A.M.或P.M.的等價符 %U 一年中的星期數(00-53)星期天爲星期的開始 %w 星期(0-6),星期天爲星期的開始 %W 一年中的星期數(00-53)星期一爲星期的開始 %x 本地相應的日期表示 %X 本地相應的時間表示 %Z 當前時區的名稱 %% %號自己
3)結構化時間(struct_time)
說明:結構化時間會輸出一個元組,元組中共有9個元素(年,月,日,時,分,秒,一年中第幾周,一年中第幾天等)
類型:<class 'time.struct_time'>;由元組組成;
查看:time.localtime #localtime是以結構化方式查看本地時間,此處還有一個gmtime是以結構化方式查看倫敦時間;
元組中的元素類說明:
索引(Index) | 屬性(Attribute) | 值(Values) |
---|---|---|
0 | tm_year(年) | 好比2011 |
1 | tm_mon(月) | 1 - 12 |
2 | tm_mday(日) | 1 - 31 |
3 | tm_hour(時) | 0 - 23 |
4 | tm_min(分) | 0 - 59 |
5 | tm_sec(秒) | 0 - 60 |
6 | tm_wday(weekday) | 0 - 6(0表示週一) |
7 | tm_yday(一年中的第幾天) | 1 - 366 |
8 | tm_isdst(是不是夏令時) | 默認爲0 |
>>> print(type(time.localtime())) #查看結構化時間的數據類型 <class 'time.struct_time'> >>> print(time.localtime()) #查看結構化時間 time.struct_time(tm_year=2018, tm_mon=8, tm_mday=20, tm_hour=15, tm_min=48, tm_sec=7, tm_wday=0, tm_yday=232, tm_isdst=0)
小結:時間戳是計算機可以識別的時間;時間字符串是人可以看懂的時間;元組則是用來操做時間的
幾種時間格式之間的轉化:
由上圖咱們可知,結構化時間起着一箇中間橋樑的做用,當格式化時間和時間戳時間相互轉換時必須先轉換成結構化時間;
接下來咱們就進行這幾種類型的轉換:
a.時間戳和結構化之間的相互轉換;
# 時間戳 ----------> 結構化時間 #time模塊有兩個方法進行轉換;time.gmtime(時間戳)、time.localtime(時間戳) #time.gmtime(時間戳),UTC時間,與英國倫敦當地時間一致 #time.localtime(時間戳),當地時間。例如咱們如今在北京執行這個方法:與UTC時間相差8小時,UTC時間+8小時 = 北京時間 ------------------------------下面開始轉換--------------------------------------- >>> import time #導入時間模塊 >>> time.gmtime(1500000000) #使用UTC時間轉換 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) #能夠看出倫敦時間和北京時間相差了8個小時; # 結構化時間 -----------> 時間戳時間 >>> struce_time = time.localtime(time.time()) #先將時間轉換爲結構化時間 >>> time.mktime(struce_time) #再將結構化時間轉換爲時間戳時間 1534752087.0
b.格式化和結構化之間的相互轉換:
# 結構化 ---------> 格式化時間 #time.strftime("格式定義","結構化時間") 結構化時間參數若不傳,則顯示當前時間 --------------------------- 例子 ------------------------------------------------- >>> import time >>> time.strftime("%F %H:%M:%S") '2018-08-20 16:05:04' >>> time.strftime("%Y-%m-%d",time.localtime()) '2018-08-20' # 格式化 ----------> 結構化時間 #time.strptime(時間字符串,字符串對應格式) ------------------------------ 例子 ---------------------------------------------- >>> time.strptime("2018-08-20","%Y-%m-%d") time.struct_time(tm_year=2018, tm_mon=8, tm_mday=20, tm_hour=0, tm_min=0, tm_sec=0, tm_wday=0, tm_yday=232, 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)
說明:這是一個取隨機數模塊,用來產生隨機數;
名稱:random
random有四種基本方式:
1)取隨機小數;
random.random()
說明:取0-1之間的小數;
>>> import random >>> print(random.random()) 0.3569863449931081
random.uniform(n,m)
說明:取指定範圍內的小數
>>> print(random.uniform(5,8)) 6.6214335271284135
2)取隨機整數;
random.randint(n,m)
說明:取指定範圍內的整數,取值包括n,m,至關於[n,m]
>>> print(random.randint(5,8)) 8
random.randrange(n,m,s)
說明:由range生成一些數,在這些數中取隨機數,取值包括n,不包括m,至關於[n,m);s表示的是步長,先由range生成數字,而後在用random取;
>>> print(random.randrange(6)) 1 >>> print(random.randrange(2,6,2)) 4 >>> print(random.randrange(2,6,2)) 2 >>> print(random.randrange(2,6,2)) 4
3)從一個列表或字符串元組等等有長度(len)的數據類型中隨機抽取值;
random.choice(n)
說明:從字符串或列表或元組等有索引的數據類型中取一個值,只取1個值;不支持集合、字典、數字;
參數:n ------- > 指定字符串或列表或元組等有索引的數據類型
>>> print(random.choice("zjksldfjl")) z >>> print(random.choice("zjksldfjl")) l >>> print(random.choice([1,"zjk",8,False])) False >>> print(random.choice([1,"zjk",8,False])) False >>> print(random.choice([1,"zjk",8,False])) 1 >>> print(random.choice([1,"zjk",8,False])) zjk >>> print(random.choice((1,"zjk",8,False))) 8
random.sample(n,c)
說明:從字符串或列表或元組等有索引的數據類型中一次取多個值;不支持集合、字典、數字;
參數:n ---------> 指定數據; c -----------> 指定一次取多值的個數
返回值:返回的是一個列表;
>>> print(random.sample([1,2,"zjk","A"],3)) ['zjk', 'A', 1]
4)打亂一個列表的順序,在原列表的基礎上直接進行修改,節省空間;
random.shuffle(list)
說明:打亂一個列表的順序,在原列表的基礎上直接進行修改,節省空間;
參數:list --------> 使用列表數據類型;
>>> li = [1,2,3,4,5,6,7,8,9] >>> random.shuffle(li) >>> print(li) [1, 2, 5, 4, 6, 8, 7, 3, 9]
實例:
#使用for循環方式 >>> st = "" >>> for n in range(4): ... num = random.randint(0,9) ... st += str(num) ... >>> print(st) 1084 # 函數版 >>> def func(n=6): ... st = "" ... for i in range(n): ... num = random.randint(0,9) ... st += str(num) ... return st ... >>> print(func()) 931404 >>> print(func(4)) 3780
#for循環方式 >>> st = "" >>> for i in range(6): ... num = str(random.randint(0,9)) ... alpha_upper = chr(random.randint(65,90)) ... alpha_lower = chr(random.randint(97,122)) ... res = random.choice([num,alpha_upper,alpha_lower]) ... st += res ... >>> print(st) KO0SnR # 函數升級版 >>> import random >>> >>> def func(n=6,alpha=True): ... st = "" ... for i in range(n): ... num = str(random.randint(0,9)) ... if alpha: ... alpha_upper = chr(random.randint(65,90)) ... alpha_lower = chr(random.randint(97,122)) ... num = random.choice([num,alpha_upper,alpha_lower]) ... st += num ... return st ... >>> print(func(4)) HI1H >>> print(func(8)) 05S7rqm3 >>> print(func(8,False)) 46654230 >>> print(func(8,False)) 09328134
說明:os模塊是與操做系統交互的一個藉口,
名稱:os
os模塊基本用途:
1)文件的操做;
os.mkdir(dirname)
# 建立一個空目錄;
os.makedirs(dirname1/diename2..)
# 遞歸建立目錄
os.rmdir(dirname)
# 刪除一個空目錄,若目錄不爲空則沒法刪除,報錯;
os.removedirs(dirname)
# 遞歸刪除空目錄,若是目錄爲空,則刪除,並遞歸到上一級目錄,若是上一級目錄也爲空,則也刪除,一次類推;
os.listdir(dirname)
# 列出指定目錄下的全部文件和子目錄,包括隱藏文件,並以列表方式進行打印;
os.remove(file)
# 刪除一個文件file
os.rename(oldname,newname)
# 文件或目錄重命名
os.stat(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)是建立時間(詳細信息參見平臺的文檔)。
2)調用系統shell類
os.system(bash command)
# 調用系統shell,有系統shell去執行;
os.popen(bash command).read()
#調用系統shell,由系統shell去執行,並將執行結果返回給python;
os.getcwd()
#獲取當前所在目錄,至關於pwd;
os.chdir(dirname)
# 切換當前所在的目錄,至關於cd;
3)系統路徑類(os.path)
os.path.abspath(path)
#返回path規範化的絕對路徑,os.path.split(path) 將path分割成目錄和文件名二元組返回;
os.path.dirname(path)
# 返回path的目錄。其實就是os.path.split(path)的第一個元素,也就是返回該文件的目錄;
os.path.basename(path)
# 返回path的文件名,其實就是返回該文件的文件名;若是這是一個目錄,則返回空值;
os.path.exists(path)
# 若是文件路徑存在則返回True,不然返回False
os.path.isabs(path)
# 若是該文件是絕對路徑,則返回True,不然返回False;
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.path.split(path)
#把一個路徑分紅兩段,第一段是目錄,第二段是一個文件或目錄
def func(path): # r'D:\sylar\s15' size_sum = 0 name_lst = os.listdir(path) for name in name_lst: path_abs = os.path.join(path,name) if os.path.isdir(path_abs): size = func(path_abs) size_sum += size else: size_sum += os.path.getsize(path_abs) return size_sum ret = func(r'D:\sylar\s15') print(ret)
思路:循環,堆棧思想。列表 知足一個順序 先進來的後出去
lst = [r'D:\sylar\s15',] # 列表的第一個目錄就是我要統計的目錄 size_sum = 0 while lst: # [r'D:\sylar\s15',] lst = ['D:\sylar\s15\day01','D:\sylar\s15\day01'..] path = lst.pop() # path = 'D:\sylar\s15' lst = [] path_list = os.listdir(path) # path_list = ['day01',day02',aaa,day15.py] for name in path_list: # name = day01 abs_path = os.path.join(path,name) if os.path.isdir(abs_path): # 文件夾的邏輯 lst.append(abs_path) # lst.append('D:\sylar\s15\day01') lst = ['D:\sylar\s15\day01'] else: size_sum += os.path.getsize(abs_path) print(size_sum)
os.sep 輸出操做系統特定的路徑分隔符,win下爲"\\",Linux下爲"/" os.linesep 輸出當前平臺使用的行終止符,win下爲"\t\n",Linux下爲"\n" os.pathsep 輸出用於分割文件路徑的字符串 win下爲;,Linux下爲: os.name 輸出字符串指示當前使用平臺。win->'nt'; Linux->'posix'
說明:sys模塊是與python解釋器交互的一個接口;
名稱:sys
sys模塊的幾個經常使用方法:
sys.argv[num]
# 用來接收命令行參數;num是數字;0表示當前腳本的位置,1表示傳入的第一個參數;2表示傳入的第2個參數;依次類推;
sys.exit(obj)
# 退出程序,正常退出時exit(0),錯誤退出sys.exit(1),obj也能夠自定義,退出時顯示obj;
sys.version
# 獲取Python解釋程序的版本信息
sys.path
# 返回模塊的搜索路徑,初始化時使用PYTHONPATH環境變量的值;
sys.platform
# 返回操做系統平臺名稱
說明:將本來的字典、列表等內容轉換成一個字符串的過程就叫作序列化;
有兩個模塊:json pickle
好比,咱們在python代碼中計算的一個數據須要給另一段程序使用,那咱們怎麼給? 如今咱們能想到的方法就是存在文件裏,而後另外一個python程序再從文件裏讀出來。 可是咱們都知道,對於文件來講是沒有字典這個概念的,因此咱們只能將數據轉換成字典放到文件中。 你必定會問,將字典轉換成一個字符串很簡單,就是str(dic)就能夠辦到了,爲何咱們還要學習序列化模塊呢? 沒錯序列化的過程就是從dic 變成str(dic)的過程。如今你能夠經過str(dic),將一個名爲dic的字典轉換成一個字符串, 可是你要怎麼把一個字符串轉換成字典呢? 聰明的你確定想到了eval(),若是咱們將一個字符串類型的字典str_dic傳給eval,就會獲得一個返回的字典類型了。 eval()函數十分強大,可是eval是作什麼的?e官方demo解釋爲:將字符串str當成有效的表達式來求值並返回計算結果。 BUT!強大的函數有代價。安全性是其最大的缺點。 想象一下,若是咱們從文件中讀出的不是一個數據結構,而是一句"刪除文件"相似的破壞性語句,那麼後果實在不堪設設想。 而使用eval就要擔這個風險。 因此,咱們並不推薦用eval方法來進行反序列化操做(將str轉換成python中的數據結構)
#可以在網絡上傳輸的只能是bytes, #可以存儲在文件裏的只有bytes和str
目的:a.以某種存儲形式使自定義對象持久化;
b.將對象從一個地方傳遞到另外一個地方;
c.使程序更具維護性;
說明:json模塊提供了四個功能:dumps、dump、loads、load
只支持:列表、數字、字符串、bytes的類型
import json dic = {'k1':'v1','k2':'v2','k3':'v3'} str_dic = json.dumps(dic) #序列化:將一個字典轉換成一個字符串 print(type(str_dic),str_dic) #<class 'str'> {"k3": "v3", "k1": "v1", "k2": "v2"} #注意,json轉換完的字符串類型的字典中的字符串是由""表示的 dic2 = json.loads(str_dic) #反序列化:將一個字符串格式的字典轉換成一個字典 #注意,要用json的loads功能處理的字符串類型的字典中的字符串必須由""表示 print(type(dic2),dic2) #<class 'dict'> {'k1': 'v1', 'k2': 'v2', 'k3': 'v3'} list_dic = [1,['a','b','c'],3,{'k1':'v1','k2':'v2'}] str_dic = json.dumps(list_dic) #也能夠處理嵌套的數據類型 print(type(str_dic),str_dic) #<class 'str'> [1, ["a", "b", "c"], 3, {"k1": "v1", "k2": "v2"}] list_dic2 = json.loads(str_dic) print(type(list_dic2),list_dic2) #<class 'list'> [1, ['a', 'b', 'c'], 3, {'k1': 'v1', 'k2': 'v2'}]
import json f = open('json_file','w') dic = {'k1':'v1','k2':'v2','k3':'v3'} json.dump(dic,f) #dump方法接收一個文件句柄,直接將字典轉換成json字符串寫入文件 f.close() f = open('json_file') dic2 = json.load(f) #load方法接收一個文件句柄,直接將文件中的json字符串轉換成數據結構返回 f.close() print(type(dic2),dic2)
import json f = open('file','w') json.dump({'國籍':'中國'},f) ret = json.dumps({'國籍':'中國'}) f.write(ret+'\n') json.dump({'國籍':'美國'},f,ensure_ascii=False) ret = json.dumps({'國籍':'美國'},ensure_ascii=False) f.write(ret+'\n') f.close()
Serialize obj to a JSON formatted str.(字符串表示的json對象) Skipkeys:默認值是False,若是dict的keys內的數據不是python的基本類型(str,unicode,int,long,float,bool,None),設置爲False時,就會報TypeError的錯誤。此時設置成True,則會跳過這類key ensure_ascii:,當它爲True的時候,全部非ASCII碼字符顯示爲\uXXXX序列,只需在dump時將ensure_ascii設置爲False便可,此時存入json的中文便可正常顯示。) If check_circular is false, then the circular reference check for container types will be skipped and a circular reference will result in an OverflowError (or worse). If allow_nan is false, then it will be a ValueError to serialize out of range float values (nan, inf, -inf) in strict compliance of the JSON specification, instead of using the JavaScript equivalents (NaN, Infinity, -Infinity). indent:應該是一個非負的整型,若是是0就是頂格分行顯示,若是爲空就是一行最緊湊顯示,不然會換行且按照indent的數值顯示前面的空白分行顯示,這樣打印出來的json數據也叫pretty-printed json separators:分隔符,其實是(item_separator, dict_separator)的一個元組,默認的就是(‘,’,’:’);這表示dictionary內keys之間用「,」隔開,而KEY和value之間用「:」隔開。 default(obj) is a function that should return a serializable version of obj or raise TypeError. The default simply raises TypeError. sort_keys:將數據根據keys的值進行排序。 To use a custom JSONEncoder subclass (e.g. one that overrides the .default() method to serialize additional types), specify it with the cls kwarg; otherwise JSONEncoder is used.
import json data = {'username':['李華','二愣子'],'sex':'male','age':16} json_dic2 = json.dumps(data,sort_keys=True,indent=2,separators=(',',':'),ensure_ascii=False) print(json_dic2)
說明:支持在python中幾乎全部的數據類型;
注意:dumps 序列化的結果只能是字節;只能在python中使用;在和文件操做的時候,須要用rb wb的模式打開文件;能夠屢次dump 和 屢次load
ith open('pickle_file','rb') as f: while True: try: ret = pickle.load(f) print(ret,type(ret)) except EOFError: break
說明:用於加密相關的操做,代替了md5模塊和sha模塊,主要提供 SHA1, SHA224, SHA256, SHA384, SHA512 ,MD5 算法;
注意:字符串字加密時須要轉換成字節形式才能夠加密;
一旦加密造成密文後是沒法解密的,尤爲是自定義key更是沒法解密,因此在進行驗證用戶時,能夠對用戶輸入的密碼進行加密而後和數據庫裏的密文進行比較,一致的話說明密碼是正確的。
import md5 hash = md5.new() hash.update('admin') print hash.hexdigest()
import sha hash = sha.new() hash.update('admin') print hash.hexdigest()
import hashlib # ######## md5 ######## hash = hashlib.md5() hash.update('admin'.encode('utf-8')) print(hash.hexdigest()) # ######## sha1 ######## hash = hashlib.sha1() hash.update('admin'.encode('utf-8')) print(hash.hexdigest()) # ######## sha256 ######## hash = hashlib.sha256() hash.update('admin'.encode('utf-8')) print(hash.hexdigest()) # ######## sha384 ######## hash = hashlib.sha384() hash.update('admin'.encode('utf-8')) print(hash.hexdigest()) # ######## sha512 ######## hash = hashlib.sha512() hash.update('admin'.encode('utf-8')) print(hash.hexdigest())
以上加密算法雖然依然很是厲害,但時候存在缺陷,即:經過撞庫能夠反解。因此,有必要對加密算法中添加自定義key再來作加密。
就是在hashlib.算法(key),括號里加key,這個key也是一個字節形式,好比:b'2erer3a',
import hashlib #注意:admin 加密後就是c5395258d82599e5f1bec3be1e4dea4a SALT = b'2erer3asdfwerxdf34sdfsdfs90' #固定一個key,切記不能修改或泄露此key, def md5(pwd): # 實例化對象 obj = hashlib.md5(SALT) # 寫入要加密的字節 obj.update(pwd.encode('utf-8')) # 獲取密文 return obj.hexdigest() user = input("請輸入用戶名:") pwd = input("請輸入密碼:") if user == 'zjk' and md5(pwd) == 'c5395258d82599e5f1bec3be1e4dea4a': print('登陸成功') else: print('登陸失敗') ------------------ 打印輸出 ---------------------------------------------- 請輸入用戶名:zjk 請輸入密碼:admin 登陸成功
hashlib不夠強大??python 還有一個 hmac 模塊。
說明:該模塊加密是先把數據存儲到字典中,而後再進行加密,方法與上述方法相似。
首先須要準備待計算的原始消息message,隨機key,哈希算法,這裏採用MD5;
import hmac message = b'Hello world' key = b'secret' h = hmac.new(key,message,digestmod='MD5') print(h.hexdigest())
可見使用hmac和普通hash算法很是相似。hmac輸出的長度和原始哈希算法的長度一致。須要注意傳入的key和message都是bytes
類型,str
類型須要首先編碼爲bytes
。
def hmac_md5(key, s): return hmac.new(key.encode('utf-8'), s.encode('utf-8'), 'MD5').hexdigest() class User(object): def __init__(self, username, password): self.username = username self.key = ''.join([chr(random.randint(48, 122)) for i in range(20)]) self.password = hmac_md5(self.key, password)
日誌是一種能夠追蹤某些軟件運行時所發生事件的方法。軟件開發人員能夠向他們的代碼中調用日誌記錄相關的方法來代表發生了某些事情。一個事件能夠用一個可包含可選變量數據的消息來描述。此外,事件也有重要性的概念,這個重要性也能夠被稱爲嚴重性級別(level)。
經過log的分析,能夠方便用戶瞭解系統或軟件、應用的運行狀況;若是你的應用log足夠豐富,也能夠分析以往用戶的操做行爲、類型喜愛、地域分佈或其餘更多信息;若是一個應用的log同時也分了多個級別,那麼能夠很輕易地分析獲得該應用的健康情況,及時發現問題並快速定位、解決問題,補救損失。
簡單來說就是,咱們經過記錄和分析日誌能夠了解一個系統或軟件程序運行狀況是否正常,也能夠在應用程序出現故障時快速定位問題。好比,作運維的同窗,在接收到報警或各類問題反饋後,進行問題排查時一般都會先去看各類日誌,大部分問題均可以在日誌中找到答案。再好比,作開發的同窗,能夠經過IDE控制檯上輸出的各類日誌進行程序調試。對於運維老司機或者有經驗的開發人員,能夠快速的經過日誌定位到問題的根源。可見,日誌的重要性不可小覷。日誌的做用能夠簡單總結爲如下3點:
程序調試
瞭解軟件程序運行狀況,是否正常
軟件程序運行故障分析與問題定位
在軟件開發階段或部署開發環境時,爲了儘量詳細的查看應用程序的運行狀態來保證上線後的穩定性,咱們可能須要把該應用程序全部的運行日誌所有記錄下來進行分析,這是很是耗費機器性能的。當應用程序正式發佈或在生產環境部署應用程序時,咱們一般只須要記錄應用程序的異常信息、錯誤信息等,這樣既能夠減少服務器的I/O壓力,也能夠避免咱們在排查故障時被淹沒在日誌的海洋裏。那麼,怎樣才能在不改動應用程序代碼的狀況下實如今不一樣的環境記錄不一樣詳細程度的日誌呢?這就是日誌等級的做用了,咱們經過配置文件指定咱們須要的日誌等級就能夠了。
不一樣的應用程序所定義的日誌等級可能會有所差異,分的詳細點的會包含如下幾個等級:
級別 | 什麼時候使用 | 數字表示 |
---|---|---|
DEBUG | 詳細信息,典型地調試問題時會感興趣。 詳細的debug信息。 | 10 |
INFO | 證實事情按預期工做。 關鍵事件。 | 20 |
WARNING | 代表發生了一些意外,或者不久的未來會發生問題(如‘磁盤滿了’)。軟件仍是在正常工做。 | 30 |
ERROR | 因爲更嚴重的問題,軟件已不能執行一些功能了。 通常錯誤消息。 | 40 |
CRITICAL | 嚴重錯誤,代表軟件已不能繼續運行了。 | 50 |
一條日誌信息對應的是一個事件的發生,而一個事件一般須要包括如下幾個內容:
事件發生時間
事件發生位置
事件的嚴重程度--日誌級別
事件內容
上面這些都是一條日誌記錄中可能包含的字段信息,固然還能夠包括一些其餘信息,如進程ID、進程名稱、線程ID、線程名稱等。日誌格式就是用來定義一條日誌記錄中包含那些字段的,且日誌格式一般都是能夠自定義的。
幾乎全部開發語言都會內置日誌相關功能,或者會有比較優秀的第三方庫來提供日誌操做功能,好比:log4j,log4php等。它們功能強大、使用簡單。Python自身也提供了一個用於記錄日誌的標準庫模塊--logging。
logging模塊是Python內置的標準模塊,主要用於輸出運行日誌,能夠設置輸出日誌的等級、日誌保存路徑、日誌文件回滾等;相比print,具有以下優勢:
能夠經過設置不一樣的日誌等級,在release版本中只輸出重要信息,而沒必要顯示大量的調試信息;
print將全部信息都輸出到標準輸出中,嚴重影響開發者從標準輸出中查看其它數據;logging則能夠由開發者決定將信息輸出到什麼地方,以及怎麼輸出。
logging模塊默認定義瞭如下幾個日誌等級,它容許開發人員自定義其餘日誌級別,可是這是不被推薦的,尤爲是在開發供別人使用的庫時,由於這會致使日誌級別的混亂。
日誌等級(level) | 描述 | 數字表示 |
---|---|---|
DEBUG | 最詳細的日誌信息,典型應用場景是 問題診斷 | 10 |
INFO | 信息詳細程度僅次於DEBUG,一般只記錄關鍵節點信息,用於確認一切都是按照咱們預期的那樣進行工做 | 20 |
WARNING | 當某些不指望的事情發生時記錄的信息(如,磁盤可用空間較低),可是此時應用程序仍是正常運行的 | 30 |
ERROR | 因爲一個更嚴重的問題致使某些功能不能正常運行時記錄的信息 | 40 |
CRITICAL | 當發生嚴重錯誤,致使應用程序不能繼續運行時記錄的信息 | 50 |
開發應用程序或部署開發環境時,可使用DEBUG或INFO級別的日誌獲取儘量詳細的日誌信息來進行開發或部署調試;
說明:
上面列表中的日誌等級是從上到下依次升高的,即:DEBUG < INFO < WARNING < ERROR < CRITICAL,而日誌的信息量是依次減小的;
當爲某個應用程序指定一個日誌級別後,應用程序會記錄全部日誌級別大於或等於指定日誌級別的日誌信息,而不是僅僅記錄指定級別的日誌信息,nginx、php等應用程序以及這裏的python的logging模塊都是這樣的。一樣,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)
函數用於指定「要記錄的日誌級別」、「日誌格式」、「日誌輸出位置」、「日誌文件的打開模式」等信息,其餘幾個都是用於記錄各個級別日誌的函數。
import logging logging.debug("debug_msg") logging.info("info_msg") logging.warning("warning_msg") logging.error("error_msg") logging.critical("critical_msg") --------------------------------- 輸出結果 -------------------------------------- WARNING:root:warning_msg ERROR:root:error_msg CRITICAL:root:critical_msg
默認狀況下Python的logging模塊將日誌打印到了標準輸出中,且只顯示了大於等於WARNING級別的日誌,這說明默認的日誌級別設置爲WARNING(日誌級別等級CRITICAL > ERROR > WARNING > INFO > DEBUG)。
默認輸出格式爲:默認的日誌格式爲日誌級別:Logger名稱:用戶輸出消息
import logging logger = logging.basicConfig(filename='xxxxxxx.txt', format='%(asctime)s - %(name)s - %(levelname)s -%(module)s: %(message)s', datefmt='%Y-%m-%d %H:%M:%S', level=30) logging.debug('x1') # 10 logging.info('x2') # 20 logging.warning('x3') # 30 logging.error('x4') # 40 logging.critical('x5') # 50
#輸出結果: #在xxxxxxxxx.txt文件中 2018-08-31 17:50:24 - root - WARNING -面向對象: x3 2018-08-31 17:50:24 - root - ERROR -面向對象: x4 2018-08-31 17:50:24 - root - CRITICAL -面向對象: x5
說明:
logging.basicConfig()
函數是一個一次性的簡單配置工具使,也就是說只有在第一次調用該函數時會起做用,後續再次調用該函數時徹底不會產生任何操做的,屢次調用的設置並非累加操做。
日誌器(Logger)是有層級關係的,上面調用的logging模塊級別的函數所使用的日誌器是RootLogger
類的實例,其名稱爲'root',它是處於日誌器層級關係最頂層的日誌器,且該實例是以單例模式存在的。
logging模塊就是經過這些組件來完成日誌處理的,上面所使用的logging模塊級別的函數也是經過這些組件對應的類來實現的。
日誌器(logger)須要經過處理器(handler)將日誌信息輸出到目標位置,如:文件、sys.stdout、網絡等;
不一樣的處理器(handler)能夠將日誌輸出到不一樣的位置;
日誌器(logger)能夠設置多個處理器(handler)將同一條日誌記錄輸出到不一樣的位置;
每一個處理器(handler)均可以設置本身的過濾器(filter)實現日誌過濾,從而只保留感興趣的日誌;
每一個處理器(handler)均可以設置本身的格式器(formatter)實現同一條日誌以不一樣的格式輸出到不一樣的地方。
簡單點說就是:日誌器(logger)是入口,真正幹活兒的是處理器(handler),處理器(handler)還能夠經過過濾器(filter)和格式器(formatter)對要輸出的日誌內容作過濾和格式化等處理操做。
import logging # 建立一個操做日誌的對象logger(依賴FileHandler) file_handler = logging.FileHandler('l1.log', 'a', encoding='utf-8') file_handler.setFormatter(logging.Formatter(fmt="%(asctime)s - %(name)s - %(levelname)s -%(module)s: %(message)s")) logger1 = logging.Logger('s1', level=logging.ERROR) logger1.addHandler(file_handler) logger1.error('123123123') # 在建立一個操做日誌的對象logger(依賴FileHandler) file_handler2 = logging.FileHandler('l2.log', 'a', encoding='utf-8') file_handler2.setFormatter(logging.Formatter(fmt="%(asctime)s - %(name)s - %(levelname)s -%(module)s: %(message)s")) logger2 = logging.Logger('s2', level=logging.ERROR) logger2.addHandler(file_handler2) logger2.error('666')
梵蒂岡梵蒂岡