python常用模塊

本節大綱:

1.模塊介紹

2.time&datetime

3.random.

4.os

5.sys

6.shutil

7.json&picle

8.shelve

9.xml處理

10.yaml處理

11.configparser

12.hashlib

13.subprocess

14.logging模塊

15.re正則表達式

模塊的定義:用一堆代碼實現了某個功能的代碼集合

類似與函數式編程和麪向過程編程,函數式編程則完成一個功能,其他代碼用來調用即可,提供了代碼的重用性和代碼間的耦合,而對於一個複雜的功能來說,可能需要多個函數才能完成(函數又可以在不同的.py文件中),n個.py文件組成的代碼集合就稱爲模塊

如:os是系統相關的模塊,file是文件操作相關的模塊

模塊分爲三種:

自定義模塊

內置模塊

開源模塊(第三方模塊)

自定義模塊

1.定義模塊

情景一

情景二

 2.導入模塊

在python中,要想使用模塊,需要先導入,導入模塊有以下幾種方式:

如要導入一個名爲module的模塊

1 import module
2 from module.xx.xx import xx
3 from module.xx.xx import xx as rename  
4 from module.xx.xx import *
#*號這種導入模式會導入一個模塊中的所有項目,這種方法雖然很簡單,便利,但是不推薦使用,
#因爲引入的其他來源的命令,很可能覆蓋了已有的定義,存在一定的安全隱患
導入模塊其實就是在告訴Python解釋器去解釋那個py文件

如果導入的是一個py文件,解釋器就解釋該py文件

如果導入的是一個包,解釋器就解釋該包下的__init__.py文件

Python中,導入模塊時是根據那個路徑作爲基準來進行的呢?

可通過sys模塊中的sys.path來查看

import sys
print(sys.path)

#['D:\\PycharmProjects\\fullstack\\homework_oneday\\module\\module_file', 'D:\\PycharmProjects\\fullstack', 'C:\\Program Files\\Python35\\python35.zip', 'C:\\Program Files\\Python35\\DLLs', 'C:\\Program Files\\Python35\\lib', 'C:\\Program Files\\Python35', 'C:\\Program Files\\Python35\\lib\\site-packages']
如果sys.path路徑列表中沒有你想要的路徑,可以通過sys.path.append('路徑')添加

通過os模塊可以獲取各種目錄

import sys
import os

pre_path = os.path.abspath('../')
sys.path.append(pre_path)
包(package)的概念

我們先設想一下,如果不同的人編寫的模塊名相同怎麼辦?爲了避免衝突,Python又引進了按目錄來組織模塊的方法,稱爲包(package)。

假設,如下圖,我的兩個time_file.py模塊名字重名了,但是這兩個模塊的功能都不相同,如果這兩個模塊都在同一級目錄中,那麼我在其他地方要調用這個time_file.py模塊,那麼這個時候就會發生衝突,在這裏我們就可以通過包來組織模塊,避免衝突,

 

方法是:選擇一個頂層包名,引入包以後,只要頂層的包名不與別人衝突,那這個包裏面的模塊都不會與別人衝突了。

請注意:每個包目錄下來都會有一個__init__.py的文件,這個文件必須是存在的,否則,Python就不把這個目錄當成普通目錄,而不是一個包,__init__.py可以是空文件,也可以有python代碼,__init__.py本身就是一個文件,它的模塊命就是對應的包名,它一般由於做接口文件

開源模塊(第三方模塊) 

一.下載安裝

下載安裝的兩種方式

1 yum
2 pip
3 apt-get
4 ...
1 下載源碼
2 解壓源碼
3 進入目錄
4 編譯源碼  python setup.py build
5 安裝源碼  python setup.py install
注:在使用源碼安裝時,需要使用到gcc編譯和Python開發環境,所以,要事先將環境安裝上

1 yum install gcc
2 yum install python-devel
3 或
4 apt-get python-dev
安裝成功後,模塊會自動安裝到sys.path中的某個目錄中,如:

1 /usr/lib/python3.5/site-packages/
導入模塊的方式同自定義模塊導入的方式一樣

 三.模塊paramiko(晚上回家補齊)

 

內置模塊

一.time()模塊

在python中,通常有以下幾種方式來表示時間:

時間戳(timestamp):通常來說,時間戳表示的是從1970年1月1日00:00:00開始按秒計算的偏移量,

格式化的時間字符串:

元組(struct_time):struct_time元組共有9個元素:(年,月,日,時,分,秒,一年中第幾周,一年中第幾天,夏令時)

1 import time

3 print(time.time())  # 返回當前時間的時間戳 1481597763.3750336
4 print(time.localtime())  # 將一個時間戳轉換爲當前時區
5 #  time.struct_time(tm_year=2016, tm_mon=12, tm_mday=13, tm_hour=10, tm_min=57, tm_sec=31, tm_wday=1, tm_yday=348, tm_isdst=0)
6 print(time.gmtime())  # localtime()方法類似,gmtime()方法是將一個時間戳轉換爲UTC時區(0時區)的struct_time。
7 #  time.struct_time(tm_year=2016, tm_mon=12, tm_mday=13, tm_hour=3, tm_min=0, tm_sec=47, tm_wday=1, tm_yday=348, tm_isdst=0)


 

 1 print(time.ctime())  # Tue Dec 13 21:29:55 2016
 2 
 3 print(time.gmtime(time.time()-9000))
 4 #返回utc時間的struc時間對象格式
 5 #time.struct_time(tm_year=2016, tm_mon=12, tm_mday=13, tm_hour=11, tm_min=2, tm_sec=17, tm_wday=1, tm_yday=348, tm_isdst=0)
 6 
 7 
 8 
 9 #日期轉換成時間戳
10 time_struct = time.strptime("2016-12-12 18:24:30","%Y-%m-%d %X")
11 print(time_struct) 
12 #time.struct_time(tm_year=2016, tm_mon=12, tm_mday=12, tm_hour=18, tm_min=24, tm_sec=30, tm_wday=0, tm_yday=347, tm_isdst=-1)
13 #將日期字符串轉換struct時間對象格式
14 
15 
16 #將struct時間對象轉換成時間戳
17 time_struct = time.strptime("2016-12-12 18:24:30","%Y-%m-%d %X")
18 time_one_struct = time.mktime(time_struct)
19 print(time_one_struct)
20 #1481538270.0
21 
22 #將時間戳轉換爲字符串格式
23 print(time.gmtime(time.time()-99999)) # 將utc時間戳轉換成struct_time格式
24 
25 #將utc struct_time格式轉換爲指定的字符串格式
26 print(time.strftime("%Y-%m-%d %X",time.gmtime()))

#sleep()  #線程推遲自定的時間運行,單位爲秒

#clock()
#這個需要注意啦,在不同的系統上含義不同,在unix系統上,它返回的是'進程時間',用秒錶示的浮點數(時間戳)
#在windows中,第一次調用,返回的是進程運行的實際時間,而第二次之後的調用是自第一次調用後到現在的運行
#的時間,即兩次的時間差


 

 1 import datetime
 2 
 3 #顯示當前時間日期
 4 print(datetime.datetime.now())
 5 #  2016-12-13 21:58:43.911173
 6 
 7 #當前時間+3天
 8 print(datetime.datetime.now() + datetime.timedelta(3))
 9 #2016-12-16 22:01:17.556961
10 
11 #當前時間-3天
12 print(datetime.datetime.now() + datetime.timedelta(-3))
13 #2016-12-10 22:04:18.496310
14 
15 #當前時間+30分
16 print(datetime.datetime.now() + datetime.timedelta(hours=3))
17 #2016-12-14 01:05:43.915196
18 
19 #時間替換
20 c_time = datetime.datetime.now()
21 print(c_time.replace(minute=3,hour=2))
22 #2016-12-13 02:03:14.949403  將小時數與分鐘數替換
23 
24 #時間戳直接轉換爲日期格式
25 print(datetime.date.fromtimestamp(time.time()))  # 2016-12-13


 

 二random模塊

 1 import random
 2 
 3 #0,1之間時間生成的浮點數  float
 4 print(random.random())
 5 
 6 #隨機生成傳入參數範圍內的數字 即 1,2,3
 7 print(random.randint(1,3))
 8 
 9 #隨機生成傳入參數範圍內的數字,range顧頭不顧尾
10 print(random.randrange(1,3))
11 
12 #隨機選擇任意一個數字
13 print(random.choice([1,'23',[4,5]]))
14 
15 #隨機選擇任意兩個數字
16 print(random.sample([1,'23',[4,5]],2))


小測試:隨機生成一個5位數的驗證碼

 1 import random
 2 
 3 def v_code():
 4     code = ''
 5     for i in range(5):
 6         num = random.randint(0,9)
 7         alf = chr(random.randint(65,90))
 8         add = random.choice([num,alf])
 9         code += str(add)
10     return code
11 result = v_code()
12 print(result)


 三.os模塊

os模塊提供對操作系統進行調用的接口

1 import os
2 print(os.getcwd())
3 獲取當前的工作目錄,即當前Python腳本工作的目錄路徑,相當於Linux中的pwd

5 print(os.chdir("當前目錄名稱/../../"))  # 改變當前腳本工作目錄,相當於shell下的cd

7 os.makedirs("dirname1/dirname2")  # 可生成多層遞歸目錄
8 os.removedirs("dirname1/dirname2")  # 若目錄爲空,則刪除,並遞歸到上一級目錄,如也爲空則刪除,以此類推


 

 1 import os
 2 
 3 # 獲取當前的工作目錄,即當前Python腳本工作的目錄路徑,相當於Linux中的pwd
 4 print(os.getcwd())
 5 
 6 
 7 print(os.chdir("D:\\PycharmProjects\\fullstack"))  # 改變當前腳本工作目錄,相當於shell下的cd
 8 
 9 os.makedirs("dirname1/dirname2")  # 可生成多層遞歸目錄
10 os.removedirs("dirname1//dirname2")  # 若目錄爲空,則刪除,並遞歸到上一級目錄,如也爲空則刪除,以此類推
11 os.mkdir("dirname")  # 生成當級目錄,相當於shell中的mkdir dirname


 

 1 os.rmdir("namedir")  # 刪除單級空目錄,若目錄不爲空則無法刪除,報錯,相當於shell中的rm dirname
 2 print(os.listdir("dirname")) # 列出指定目錄下的所有文件和子目錄,包括隱藏文件,並以列表的方式打印
 3 os.remove("filename")  # 刪除一個文件
 4 os.rename("oldname","newname")  # 重命名文件/目錄
 5 os.stat("path/filename")  # 獲取文件/目錄信息
 6 print(os.sep)  #  輸出操作系統特定的路徑分隔符,win下爲'\\',Linux下爲'/'
 7 print(os.linesep)  # 輸出當前平臺使用的行終止符,win下爲'\t\n',Linux下爲'\n'
 8 print(os.pathsep)  # 輸入用戶分割文件路徑的字符串
 9 print(os.name)  # 輸出字符串指示當前使用平臺,win->'nt',Linux->'posix'
10 print(os.system("bash command"))  # 運行shell命令,直接顯示
11 print(os.environ)  # 獲取系統環境變量
12 print(os.path.abspath(path))  # 返回path規範化的絕對路徑
13 print(os.path.split(path))  # 將path分割成目錄和文件名,二元組返回
14 print(os.path.dirname(path)) # 返回path的目錄,其實就是os.path.split(path)的第一個元素
15 print(os.path.basename(path))  # 返回path最後的文件名,如果path以/或\結尾,就會返回空值
16 print(os.path.exists(path)) # 如果path存在,返回True,如果不存在,就返回False
17 print(os.path.isabs(path))  # 如果path是絕對路徑返回True,不存在返回False
18 print(os.path.join(path1[,path2[,path3]])) # 將多個路勁組合後返回,
19 print(os.path.join(path1,path2,**)) # 將多個路徑組合後返回,第一個絕對路徑之前的參數將被忽略
20 
21 #返回path所指向的文件或者目錄的最後存取時間,可通過time模塊,轉換時間格式
22 a = os.path.getatime(r"D:\PycharmProjects\fullstack\homework_oneday\module\module_file")
23 print(time.gmtime(a))
24 
25 print(os.path.getmtime(path))  #返回path指向的文件或者目錄的最後修改時間


四.sys模塊

1 import sys
2 sys.argv  # 命令行參數List,第一個元素是程序本身路徑
3 sys.version  # 獲取Python解釋程序的版本信息
4 sys.exit(n)  # 退出程序,正常退出時exit(0)
5 sys.path  # 返回模塊的搜索路勁,初始話時使用PYTHONPATH環境變量的值
6 sys.platform  # 返回操作系統平臺名稱
7 sys.stdout.write('please:')  # 標誌輸出
8 val = sys.stdin.readline()[:-1]


小測試:進度條

1 import sys, time
2 for i in range(10):
3     sys.stdout.write("#")
4     time.sleep(1)
5     sys.stdout.flush()
五.json&pickle

在Python中有一個eval內置方法,可以還原對象原始的數據類型,不過,eval方法是有侷限性的,不是任何場合都可以使用,對應普通的數據類型,json.loads和eval都能用,eval就不管用了,所以eval的重點還是通常用來執行一個字符串表達式,並返回表達式的值

1 x = "[null,true,false]"
2 print(eval(x))  # eval會報錯
3 print(json.loads(x))
什麼是序列化

我們把對象(變量)從內存中變成可存儲或傳輸的過程稱之爲序列化。在Python中叫picking,在其他語言爲

serialization,marshalling,flattening等等,都是一個意思。

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

反過來,把變量內容從序列化的對象從新讀到內存裏稱之爲反序列化,即unpicking.

json

如果我們要在不同的編程語言之間傳遞對象,就必須把對象序列化爲標準格式,比如xml,但更好的方法是序列化爲json,因爲json表示出來就是一個字符串,可以被所有語言讀取,也可以方便的存儲到磁盤或者通過網絡傳輸,json不僅是標準格式,並且比xml更快,而且可以直接在web頁面中讀取,非常方便

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

 

 1 import json
 2 
 3 dic = {"name":"alex","age":23,"sex":"male"}
 4 j = json.dumps(dic)
 5 print(type(j))  # <class 'str'>
 6 
 7 
 8 f = open('json_file.txt','w',encoding='utf-8')
 9 f.write(j)   #----------等價於json.dump(dic,f)
10 f.close()
11 
12 
13 #----------------反序列化
14 f = open('json_file.txt','r',encoding='utf-8')
15 data = json.loads(f.read())
16 print(data,type(data))
17 f.close()
18 # {'sex': 'male', 'name': 'alex', 'age': 23} <class 'dict'>
19 
20 注意事項:json 不認單引號,如果你要將你的代碼,轉爲json類型,那麼在你的代碼中請使用雙引號
21 dic = '{"a":"abc"}'
22 print(json.loads(dic))


pickle

 1 import pickle
 2 
 3 dic = {"name":"alex","age":23,"sex":"male"}
 4 print(type(dic))  # <class 'dict'>
 5 
 6 j = pickle.dumps(dic)
 7 print(type(j))  # <class 'bytes'>
 8 
 9 f = open('test_pickle.txt','wb')  #注意w是寫入str,wb是寫入bytes,j是'bytes'
10 f.write(j)  #-------------------等價於pickle.dump(dic,f)
11 f.close()
12 
13 #------------------反序列化
14 f = open("test_pickle.txt","rb")
15 data = pickle.loads(f.read())  # 等價於data = pickle.load(f)
16 f.close()
17 print(data["age"])  # 23


pickle的問題和所有其他編程語言特有的序列化問題一樣,就是它只能用於Python,並且可能不同版本的Python彼此

都不兼容,因此,只能用pickle保存那些不重要的數據,不能成功地反序列化也沒關係

 六 shelve模塊

skelve模塊比pickle模塊簡單,只有一個open函數,返回類似字典的對象,可讀可寫,key必須爲字符串,而值可以是python所支持的所有的數據類型

1 import shelve
2 f = shelve.open('shelve_file.txt')
3 # f["stu1_info"] = {"name":"jack","age":"18"}
4 # f["stu2_info"] = {"name":"rain","age":"21"}
5 # f["stu3_info"] = {"name":"tom","age":"34"}
6 # f.close()
7 print(f.get("stu1_info"))  # {'name': 'jack', 'age': '18'}
8 print(f.get("stu1_info")["age"])  # 18


7 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 tree = ET.parse("xml_file.xml")
 3 root = tree.getroot()  #獲取xml文件對象
 4 print(root.tag)  # data
 5 
 6 # 遍歷xml文檔
 7 for item in root:
 8     print(item.tag,item.attrib)
 9     for i in item:
10         print(i.tag,i.attrib)
11 
12 # 只遍歷year節點
13 for node in root.iter("year"):
14     print(node.tag,node.text)
15 
16 
17 # 修改
18 for node in root.iter("year"):
19     new_year = int(node.text) +1
20     node.text = str(new_year)
21     node.set("updated","yes")
22 tree.write("xml_file.xml")
23 
24 # 刪除
25 for country in root.findall('country'):
26     rank = int(country.find('rank').text)
27     if rank > 50:
28         root.remove(country)
29 
30 tree.write('output.xml')


自己創建xml文檔

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


 8 configparser模塊

用於對特定的配置進行操作,當前模塊的名稱在Python3.x版本中變更爲configparser

我們來看一下Linux中常見軟件,配置格式如下:

 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 config["bitbucket.org"] = {}
 8 config["bitbucket.org"]["User"] = "jack"
 9 config["topsecret.server.com"] = {}
10 topsecret = config["topsecret.server.com"]
11 topsecret["Host Port"] = "5002"
12 topsecret["Forwardx11"] = "no"
13 config["DEFAULT"]["Forwardx11"] = "yes"
14 with open("example.ini" ,"w",encoding="utf-8") as configfile:
15     config.write(configfile)


增刪改查

 1 import configparser
 2 config = configparser.ConfigParser()
 3 # 查
 4 print(config.sections())  # []
 5 config.read("example.ini")
 6 print(config.sections())  # ['bitbucket.org', 'topsecret.server.com']
 7 print("bytebong.com" in config)  # False
 8 print(config["bitbucket.org"]["User"])  # jack
 9 print(config["topsecret.server.com"]["Forwardx11"])  # no
10 for key in config["bitbucket.org"]:
11     print(key)
12 
13 #user
14 #compressionlevel
15 #serveraliveinterval
16 #compression
17 #forwardx11
18 
19 print(config.options("bitbucket.org"))
20 # ['user', 'compressionlevel', 'serveraliveinterval', 'compression', 'forwardx11']
21 print(config.items("bitbucket.org"))
22 # [('compressionlevel', '9'), ('serveraliveinterval', '45'), ('compression', 'yes'), ('forwardx11', 'yes'), ('user', 'jack')]
23 print(config.get("bitbucket.org","compression"))  # yes


 1 #---------------------------------------------刪,改,增
 2 (config.write(open('i.cfg', "w")))
 3 
 4 
 5 config.add_section('yuan')
 6 
 7 config.remove_section('topsecret.server.com')
 8 config.remove_option('bitbucket.org','user')
 9 
10 config.set('bitbucket.org','k1','11111')
11 
12 config.write(open('i.cfg', "w"))


9 hashlib

用於加密相關的操作,代替了md5模塊和sha模塊,只要提供SHA1,SHA224,SHA256,SHA384,SHA512,MD5算法

import md5
hash = md5.new()
hash.update('admin')
print hash.hexdigest()
import sha

hash = sha.new()
hash.update('admin')
print hash.hexdigest()


 1 import hashlib
 2 m = hashlib.md5()  # m = hashlib.sha256
 3 m.update("admin".encode("utf-8"))
 4 print(m.hexdigest())  # 21232f297a57a5a743894a0e4a801fc3
 5 
 6 m.update("jack".encode("utf-8"))
 7 print(m.hexdigest())  # f75c16c62166e263e5f8d84881c15de9
 8 
 9 m2 = hashlib.md5()
10 m2.update("jack".encode("utf-8"))
11 print(m2.hexdigest())  # 4ff9fc6e4e5d5f590c4f2134a8cc96d1
12 
13 
14 m3 = hashlib.md5()
15 m3.update("hellejack".encode("utf-8"))
16 print(m3.hexdigest())  # 7a477fa1d4918d6af53fc6115e5b4376


以上的加密算法雖然非常厲害,但還是存在缺陷,即:通過撞庫可以反解,所以,有必要對加密算法中添加自定義key再來做加密

1 import hashlib
2 m = hashlib.md5("dfs9Ys".encode("utf-8"))
3 m.update("jack".encode("utf-8"))
4 print(m.hexdigest())  # 3566e566a677ba0fb8b7ec637ff707a9
python中還有一個hmac模塊,它對我們創建key和內容再進行處理然後再加密

1 import hmac
2 h = hmac.new("hello".encode("utf-8"))
3 h.update("jack".encode("utf-8"))  # 8570e3f986ef9099bfcd2e46181d0be7
4 print(h.hexdigest())
10.logging

用於便捷記錄日誌且線程安全的模塊

一,簡單應用

import logging
logging.debug("debug message")
logging.info("info message")
logging.warning("warning message")
logging.error("error message")
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
默認的日誌格式

WARNING:root:warning message
日誌級別:logger名稱:用戶輸出消息


二.靈活配置日誌級別,日誌格式,輸出位置

 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')


查看輸出

Sat, 12 Nov 2016 05:58:47 logg.py[line:9] DEBUG debug message
Sat, 12 Nov 2016 05:58:47 logg.py[line:10] INFO info message
Sat, 12 Nov 2016 05:58:47 logg.py[line:11] WARNING warning message
Sat, 12 Nov 2016 05:58:47 logg.py[line:12] ERROR error message
Sat, 12 Nov 2016 05:58:47 logg.py[line:13] CRITICAL critical message

在logging.bashicConfit()函數可通過具體參數來更改logging模塊默認行爲.

filename:用指定的文件名創建FiledHandler,這樣日誌會被存儲在指定的文件中

filemode:文件打開方式,在指定了filename時使用這個參數,默認值爲'a',可指定爲'w'

format:指定handler使用的日誌顯示格式

datefmt:指定日期時間格式

level:設置rootlogger的日誌級別

stream:用指定的stream創建StreamHandler,可以指定輸出到sys.stderr,sys.stdout或者文件

    (f = open'test.log','w'),默認爲sys.stderr,若同時列出了filename和stream兩個參數,

    則stream參數會被忽略

format參數中可能用到的格式化串:

%(name)s: logger的名字

%(levelno)s:數字形式的日記級別

%(levelname)s:文本形式的日子級別

%(pathname)s:調用日誌輸出函數的模塊的完整路徑名,可能沒有

%(filename)s:調用日誌輸出函數的文件名

%(module)s:調用日誌輸出函數的模塊名

%(funcName)s:調用日誌輸出函數的函數名

%(lineno)d:調用日誌輸出函數的語句所在的代碼行

%(created)f:當前時間,用Unix標準的表示時間的浮點數表示

%(relativeCreated)d:輸出日誌信息時的,自logger創建以來的毫秒數

%(asctime)s:字符串形式的當前時間,默認格式是"2003-07-08 16:49:45,896".逗號後面的是毫秒

%(thread)d:線程ID,可能沒有

%(threadName)s:線程名,可能沒有

%(process)d:進程ID,可能沒有

%(message)s:用戶輸出的消息

三.logger對象

上述幾個例子中,我們瞭解到了logging.debug(),logging.info(),logging.warning(),logging.error(),

logging.critical()分別用以記錄不同級別的日誌信息,logging.basicConfig()用默認日誌格式(Formatter)爲日誌

系統建立一個默認的流處理器(StreamHandler),設置基於配置(如日誌級別等),並加到root logger(根logger中)這幾個logging模塊級別的函數,另外還有一個模塊級別的函數是logging.getLogger([name])(返回一個logger對象,如果沒有指定名字將返回root logger)

在這裏我們先來看一個最簡單的過程:

 

 1 import logging
 2 
 3 logger = logging.getLogger()
 4 # 創建一個handler,用於寫入日誌文件
 5 fh = logging.FileHandler('test.log')
 6 
 7 # 再創建一個handler,用於輸出到控制檯
 8 ch = logging.StreamHandler()
 9 
10 formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
11 
12 fh.setFormatter(formatter)
13 ch.setFormatter(formatter)
14 
15 logger.addHandler(fh) #logger對象可以添加多個fh和ch對象
16 logger.addHandler(ch)
17 
18 logger.debug('logger debug message')
19 logger.info('logger info message')
20 logger.warning('logger warning message')
21 logger.error('logger error message')
22 logger.critical('logger critical message')


先簡單介紹一下,logging庫提供了多個組件:

Logger:對象提供應用程序可直接使用的接口

Handler:發送日誌到適當的目的地

Filter:提供了過濾日誌信息發方法

Formatter:指定日誌顯示格式

1.Logger是一個樹形層級結構,輸出信息之前都要獲得一個Logger(如果沒有顯示的獲取則自動創建並使用

root Logger)

 

logger=logging.getLogger()返回一個默認的Logger也即root Logger,並應用默認的日誌級別,Handler和Formatter設置。

 

也可以通過Logger.setLevel(lel)指定最低的日誌級別,可用的日誌級別有logging.DEBUG,logging.INFO,logging.WARNING,logging.ERROR,logging.CRITICAL.

 

Logger.debug()、Logger.info()、Logger.warning()、Logger.error()、Logger.critical()分別輸出不同級別的日誌,只有日誌等級大於或等於設置的日誌級別的日誌纔會被輸出

1 logger.debug('logger debug message')  
2 logger.info('logger info message')  
3 logger.warning('logger warning message')  
4 logger.error('logger error message')  
5 logger.critical('logger critical message') 
只輸出了

2016-12-15 16:32:57,329 - root - WARNING - logger warning message
2016-12-15 16:32:57,329 - root - ERROR - logger error message
2016-12-15 16:32:57,330 - root - CRITICAL - logger critical message

從這個輸出可以看出logger = logging.getLogger()返回的Logger名爲root。這裏沒有用logger.setLevel(logging.Debug)顯示的爲logger設置日誌級別,所以使用默認的日誌級別WARNIING,故結果只輸出了大於等於WARNIING級別的信息。

2.如果我們在創建兩個logger對象

 

 1 logger1 = logging.getLogger('mylogger')
 2 logger1.setLevel(logging.DEBUG)
 3 
 4 logger2 = logging.getLogger('mylogger')
 5 logger2.setLevel(logging.INFO)
 6 
 7 logger1.addHandler(fh)
 8 logger1.addHandler(ch)
 9 
10 logger2.addHandler(fh)
11 logger2.addHandler(ch)
12 
13 logger1.debug('logger1 debug message')
14 logger1.info('logger1 info message')
15 logger1.warning('logger1 warning message')
16 logger1.error('logger1 error message')
17 logger1.critical('logger1 critical message')
18   
19 logger2.debug('logger2 debug message')
20 logger2.info('logger2 info message')
21 logger2.warning('logger2 warning message')
22 logger2.error('logger2 error message')
23 logger2.critical('logger2 critical message')


輸出結果

2016-12-15 17:22:34,837 - mylogger - INFO - logger1 info message
2016-12-15 17:22:34,837 - mylogger - INFO - logger1 info message
2016-12-15 17:22:34,837 - mylogger - WARNING - logger1 warning message
2016-12-15 17:22:34,837 - mylogger - WARNING - logger1 warning message
2016-12-15 17:22:34,837 - mylogger - ERROR - logger1 error message
2016-12-15 17:22:34,837 - mylogger - ERROR - logger1 error message
2016-12-15 17:22:34,837 - mylogger - CRITICAL - logger1 critical message
2016-12-15 17:22:34,837 - mylogger - CRITICAL - logger1 critical message
2016-12-15 17:22:34,838 - mylogger - INFO - logger2 info message
2016-12-15 17:22:34,838 - mylogger - INFO - logger2 info message
2016-12-15 17:22:34,838 - mylogger - WARNING - logger2 warning message
2016-12-15 17:22:34,838 - mylogger - WARNING - logger2 warning message
2016-12-15 17:22:34,838 - mylogger - ERROR - logger2 error message
2016-12-15 17:22:34,838 - mylogger - ERROR - logger2 error message
2016-12-15 17:22:34,838 - mylogger - CRITICAL - logger2 critical message
2016-12-15 17:22:34,838 - mylogger - CRITICAL - logger2 critical message

這裏有兩個個問題:

      <1>我們明明通過logger1.setLevel(logging.DEBUG)將logger1的日誌級別設置爲了DEBUG,爲何顯示的時候沒有顯示出DEBUG級別的日誌信息,而是從INFO級別的日誌開始顯示呢?

       原來logger1和logger2對應的是同一個Logger實例,只要logging.getLogger(name)中名稱參數name相同則返回的Logger實例就是同一個,且僅有一個,也即name與Logger實例一一對應。在logger2實例中通過logger2.setLevel(logging.INFO)設置mylogger的日誌級別爲logging.INFO,所以最後logger1的輸出遵從了後來設置的日誌級別。

      <2>爲什麼logger1、logger2對應的每個輸出分別顯示兩次?
       這是因爲我們通過logger = logging.getLogger()顯示的創建了root Logger,而logger1 = logging.getLogger('mylogger')創建了root Logger的孩子(root.)mylogger,logger2同樣。而孩子,孫子,重孫……既會將消息分發給他的handler進行處理也會傳遞給所有的祖先Logger處理。

        ok,那麼現在我們把

# logger.addHandler(fh)

# logger.addHandler(ch)  註釋掉,我們再來看效果:

2016-12-15 17:24:09,250 - mylogger - INFO - logger1 info message
2016-12-15 17:24:09,251 - mylogger - WARNING - logger1 warning message
2016-12-15 17:24:09,251 - mylogger - ERROR - logger1 error message
2016-12-15 17:24:09,251 - mylogger - CRITICAL - logger1 critical message
2016-12-15 17:24:09,251 - mylogger - INFO - logger2 info message
2016-12-15 17:24:09,251 - mylogger - WARNING - logger2 warning message
2016-12-15 17:24:09,251 - mylogger - ERROR - logger2 error message
2016-12-15 17:24:09,251 - mylogger - CRITICAL - logger2 critical message

因爲我們註釋了logger對象顯示的位置,所以才用了默認方式,即標準輸出方式。因爲它的父級沒有設置文件顯示方式,所以在這裏只打印了一次。

孩子,孫子,重孫……可逐層繼承來自祖先的日誌級別、Handler、Filter設置,也可以通過Logger.setLevel(lel)、Logger.addHandler(hdlr)、Logger.removeHandler(hdlr)、Logger.addFilter(filt)、Logger.removeFilter(filt)。設置自己特別的日誌級別、Handler、Filter。若不設置則使用繼承來的值。

<3>Filter
     限制只有滿足過濾規則的日誌纔會輸出。
     比如我們定義了filter = logging.Filter('a.b.c'),並將這個Filter添加到了一個Handler上,則使用該Handler的Logger中只有名字帶          a.b.c前綴的Logger才能輸出其日誌。

 

 filter = logging.Filter('mylogger') 

     logger.addFilter(filter)

     這是隻對logger這個對象進行篩選

     如果想對所有的對象進行篩選,則:

      filter = logging.Filter('mylogger') 

      fh.addFilter(filter)

      ch.addFilter(filter)

      這樣,所有添加fh或者ch的logger對象都會進行篩選。

完整代碼1:

 1 import logging
 2 
 3 logger = logging.getLogger()
 4 # 創建一個handler,用於寫入日誌文件
 5 fh = logging.FileHandler('test.log')
 6 
 7 # 再創建一個handler,用於輸出到控制檯
 8 ch = logging.StreamHandler()
 9 
10 formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
11 
12 fh.setFormatter(formatter)
13 ch.setFormatter(formatter)
14 
15 # 定義一個filter
16 filter = logging.Filter('mylogger')
17 fh.addFilter(filter)
18 ch.addFilter(filter)
19 
20 # logger.addFilter(filter)
21 logger.addHandler(fh)
22 logger.addHandler(ch)
23 
24 
25 
26 
27 logger.setLevel(logging.DEBUG)
28 
29 logger.debug('logger debug message')
30 logger.info('logger info message')
31 logger.warning('logger warning message')
32 logger.error('logger error message')
33 logger.critical('logger critical message')
34 
35 ##################################################
36 logger1 = logging.getLogger('mylogger')
37 logger1.setLevel(logging.DEBUG)
38 
39 logger2 = logging.getLogger('mylogger')
40 logger2.setLevel(logging.INFO)
41 
42 logger1.addHandler(fh)
43 logger1.addHandler(ch)
44 
45 logger2.addHandler(fh)
46 logger2.addHandler(ch)
47 
48 logger1.debug('logger1 debug message')
49 logger1.info('logger1 info message')
50 logger1.warning('logger1 warning message')
51 logger1.error('logger1 error message')
52 logger1.critical('logger1 critical message')
53 
54 logger2.debug('logger2 debug message')
55 logger2.info('logger2 info message')
56 logger2.warning('logger2 warning message')
57 logger2.error('logger2 error message')
58 logger2.critical('logger2 critical message')


完整代碼2

#coding:utf-8  
import logging  
  
# 創建一個logger    
logger = logging.getLogger()  
  
logger1 = logging.getLogger('mylogger')  
logger1.setLevel(logging.DEBUG)  
  
logger2 = logging.getLogger('mylogger')  
logger2.setLevel(logging.INFO)  
  
logger3 = logging.getLogger('mylogger.child1')  
logger3.setLevel(logging.WARNING)  
  
logger4 = logging.getLogger('mylogger.child1.child2')  
logger4.setLevel(logging.DEBUG)  
  
logger5 = logging.getLogger('mylogger.child1.child2.child3')  
logger5.setLevel(logging.DEBUG)  
  
# 創建一個handler,用於寫入日誌文件    
fh = logging.FileHandler('/tmp/test.log')  
  
# 再創建一個handler,用於輸出到控制檯    
ch = logging.StreamHandler()  
  
# 定義handler的輸出格式formatter    
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')  
fh.setFormatter(formatter)  
ch.setFormatter(formatter)  
  
#定義一個filter  
#filter = logging.Filter('mylogger.child1.child2')  
#fh.addFilter(filter)    
  
# 給logger添加handler    
#logger.addFilter(filter)  
logger.addHandler(fh)  
logger.addHandler(ch)  
  
#logger1.addFilter(filter)  
logger1.addHandler(fh)  
logger1.addHandler(ch)  
  
logger2.addHandler(fh)  
logger2.addHandler(ch)  
  
#logger3.addFilter(filter)  
logger3.addHandler(fh)  
logger3.addHandler(ch)  
  
#logger4.addFilter(filter)  
logger4.addHandler(fh)  
logger4.addHandler(ch)  
  
logger5.addHandler(fh)  
logger5.addHandler(ch)  
  
# 記錄一條日誌    
logger.debug('logger debug message')  
logger.info('logger info message')  
logger.warning('logger warning message')  
logger.error('logger error message')  
logger.critical('logger critical message')  
  
logger1.debug('logger1 debug message')  
logger1.info('logger1 info message')  
logger1.warning('logger1 warning message')  
logger1.error('logger1 error message')  
logger1.critical('logger1 critical message')  
  
logger2.debug('logger2 debug message')  
logger2.info('logger2 info message')  
logger2.warning('logger2 warning message')  
logger2.error('logger2 error message')  
logger2.critical('logger2 critical message')  
  
logger3.debug('logger3 debug message')  
logger3.info('logger3 info message')  
logger3.warning('logger3 warning message')  
logger3.error('logger3 error message')  
logger3.critical('logger3 critical message')  
  
logger4.debug('logger4 debug message')  
logger4.info('logger4 info message')  
logger4.warning('logger4 warning message')  
logger4.error('logger4 error message')  
logger4.critical('logger4 critical message')  
  
logger5.debug('logger5 debug message')  
logger5.info('logger5 info message')  
logger5.warning('logger5 warning message')  
logger5.error('logger5 error message')  
logger5.critical('logger5 critical message')  


應用示例

import os
import time
import logging
from config import settings


def get_logger(card_num, struct_time):

    if struct_time.tm_mday < 23:
        file_name = "%s_%s_%d" %(struct_time.tm_year, struct_time.tm_mon, 22)
    else:
        file_name = "%s_%s_%d" %(struct_time.tm_year, struct_time.tm_mon+1, 22)

    file_handler = logging.FileHandler(
        os.path.join(settings.USER_DIR_FOLDER, card_num, 'record', file_name),
        encoding='utf-8'
    )
    fmt = logging.Formatter(fmt="%(asctime)s :  %(message)s")
    file_handler.setFormatter(fmt)

    logger1 = logging.Logger('user_logger', level=logging.INFO)
    logger1.addHandler(file_handler)
    return logger1


 

11.re

re模塊用於對Python的正則表達式的操作

 

1.普通字符:大多數字字符額字母都會和自身匹配

re.findall('laiying','jacklaiyinghduekdf')

2.元字符: . ^ $ * + ? {} [] | () \

#########

字符:

. 匹配除換行符以外的任意字符
\w 匹配字母或數字或下劃線或漢字
\s 匹配任意的空白符
\d 匹配數字
\b 匹配單詞的開始或結束
^ 匹配字符串的開始
$ 匹配字符串的結束

次數:

* 重複零次或更多次
+ 重複一次或更多次
? 重複零次或一次
{n} 重複n次
{n,} 重複n次或更多次
{n,m} 重複n到m次

 1 import re
 2 # result = re.findall('j..k','helljldklivi')
 3 # print(result)  # ['jldk'] . 匹配除換行符以外的任意字符
 4 
 5 # result = re.findall('^a...n','adhinhellakn')
 6 # print(result)  # ['adhin']  ^    匹配字符串的開始
 7 
 8 # result = re.findall('a.n$','adhinhellakn')
 9 # print(result)  # ['akn']  $    匹配字符串的結束
10 
11 # result = re.findall('abc*','abcabcabcccccc')
12 # print(result)  # ['abc', 'abc', 'abcccccc']  * 重複零次或更多次,貪婪模式
13 
14 # result = re.findall('abc+','abcabccccc')  # ['abc', 'abccccc'] +    重複一次或更多次
15 # print(result)
16 
17 # result = re.findall('abc?','abcabccccc') # ['abc', 'abc']  ?    重複零次或一次
18 # print(result)
19 
20 # result = re.findall('abc{2}','abcadcabccc')  # ['abcc']
21 # print(result)
22 #{n}    重複n次
23 #{n,}    重複n次或更多次
24 #{n,m}    重複n到m次


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

1 result = re.findall('abc*?','abcabcabccccc')
2 print(result)  # ['ab', 'ab', 'ab']
元字符之字符集[]

 1 #-----------字符集[],匹配[]字符集中的任意字符
 2 result = re.findall('a[bc]d','abdcabcadbacdccddd')
 3 print(result)  # ['abd', 'acd']
 4 
 5 result = re.findall('[a-z]','ahdnz')
 6 print(result)  # ['a', 'h', 'd', 'n', 'z']
 7 
 8 result = re.findall('[.*+]','a.bcd+d*d')
 9 print(result)  # ['.', '+', '*']
10 
11 #在字符集裏有功能的符號: - ^ \
12 result = re.findall('[1-9]','65dhadj3')
13 print(result)  # ['6', '5', '3']
14 
15 result = re.findall('[^abc]','aidhabcy2')
16 print(result)  # ['i', 'd', 'h', 'y', '2']  ^或
17 
18 result = re.findall('[\d]','14adb8')
19 print(result)  # ['1', '4', '8']  \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 # -------------------eg1
 2 result = re.findall('I\b','I am LIST')
 3 print(result)  # []
 4 result = re.findall(r'I\b','I am LIST')
 5 print(result)  # ['I']
 6 
 7 result = re.findall('c\1','abc\le')
 8 print(result)  # []
 9 
10 result = re.findall('c\\l','abc\le')
11 print(result)  # []
12 
13 result = re.findall('c\\\\l','abc\le')
14 print(result)  # ['c\\l']
15 
16 result = re.findall(r'c\\l','abc\le')
17 print(result)  # ['c\\l']
18 
19 # ------------------eg2
20 #之所以選擇\b是因爲\b在ASCII表中是有意義的
21 m = re.findall('\bblow','blow')
22 print(m)  # []
23 
24 m = re.findall(r'\bblow','blow')
25 print(m)  # ['blow']


元字符之分組()

1 result = re.search('(?P<id>\d{2})/(?P<name>\w{3})','23/com')
2 print(result.group())   # 23/com
3 print(result.group('id'))  # 23
4 print(result.group('name')) # com
元字符之| 或

1 result = re.search('(ab)|\d','dyabhy34dabyab')
2 print(result.group())  # ab
re模塊下的常用方法

 

 1 #re.findall() 返回所有滿足匹配條件的結果,放到列表中
 2 # result = re.findall('a','laiavie')
 3 # print(result)  # ['a', 'a']
 4 
 5 
 6 #函數會在字符串內查找模式匹配,直到找到第一個匹配的字符,就不在往下找了
 7 #通過調用group()方法得到匹配的字符串,如果字符串沒有匹配,則返回None
 8 # result = re.search('a','laiavie')
 9 # print(result.group())  # a
10 
11 
12 #同search,不過只在字符串開始處進行匹配,如果沒有匹配的字符串就報錯
13 # result = re.match('a','abc')
14 # print(result.group())  # a
15 
16 # result = re.split('[ab]','abcd')
17 # print(result)  # ['', '', 'cd']
18 #先按'a'分割得到''和'bcd',在對''和'bcd'分別按'b'分割
19 
20 
21 #sub替代字符串的內容,subn也是匹配,他會告訴你匹配了幾次
22 # result = re.sub('\d','abc','alvin5yuan6',1)
23 # print(result)  # alvinabcyuan6
24 
25 # result = re.subn('\d','abc','alvin5yuan6')
26 # print(result) # ('alvinabcyuanabc', 2)
27 
28 #編譯compile
29 # obj = re.compile('\d{2}')
30 # ret = obj.search('abc123eeee')
31 # print(ret.group())  # 12
32 
33 # result = re.finditer('\d','ys34ys3ad35')
34 # print(result)  # <callable_iterator object at 0x0000000001194B38>
35 # print(next(result).group())  # 3


注意:

1 result = re.findall('www.(baidu|oldboy).com','www.oldboy.com')
2 print(result)
3 # ['oldboy']因爲findall會優先把匹配結果組裏的內容返回,如果想要匹配結果,取消權限即可

5 result = re.findall('www.(?:baidu|oldboy).com','www.oldboy.com')
6 print(result)  # ['www.oldboy.com']

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章