一,module模塊和包的介紹html
1,在Python中,一個.py文件就稱之爲一個模塊(Module)。node
2,使用模塊的好處?python
最大的好處是大大提升了代碼的可維護性web
其次,編寫代碼沒必要從零開始,咱們編寫程序的時候,也常常引用其餘模塊,包括Python內置的模塊和來自第三方的模塊算法
另外,使用模塊還能夠避免函數名和變量名衝突。相同名字的函數和變量徹底能夠分別存在不一樣的模塊中,所以,沒必要考慮名字會與其餘模塊衝突。可是也要儘可能不與內置函數名字衝突。shell
3,種類json
1)python標準庫windows
2)第三方模塊網絡
3)自定義模塊app
4,文件夾和包的區別是,包裏面有__init__.py文件。包能夠用來組織有關係的一組文件,放在不一樣包裏還能夠避免模塊名字衝突
5,使用import導入模塊
1)例子
cal.py文件
print("ok1") def add(x,y): return x+y def sub(x,y): return x-y print("ok2")
main.py文件
import cal print(cal.add(3,7))
執行main.py文件輸出
ok1
ok2
10
說明import一個文件,首先會執行裏面的代碼。可是通常咱們在cal.py裏面定義功能性代碼,執行放到一個文件裏面
2)做用
a,執行裏面的代碼
b,導入變量名:cal
3)導入多個模塊import module1,module2,module3
4)加入from語句做用,導入具體函數能夠不使用cal.add(3,7)形式,而直接使用add(3,7)
from cal import add print(add(3,7))
from module1 import *表明導入全部函數,可是這種方法不推薦。不推薦的理由在於,這樣使用會導入一些本身不知道的函數名,若是在調用文件裏本身起了重名函數,具體調用哪一個將取決於from module1 import *和定義同名函數的相對位置。
使用from語句後,雖然能夠導入某個具體函數,可是該py文件也和上面同樣會所有執行
5)路徑
運行某個py文件,會自動把其路徑加入到sys.path裏面,這樣在這個路徑下面的文件均可以使用import找到。而sys.path還包含一些python庫的路徑等等。有個須要注意的地方是Pycharm還會在sys.path裏面添加工程文件的路徑,更方便使用吧。
須要注意的是上面提到的路徑只是執行文件的路徑,若是導入的文件在其下一層,則須要把下一層的文件夾(或者包)加入到import語句中來。舉個例子:目錄結構以下,這裏面my_module是一個文件夾
bin.py
my_module--cal.py
--main.py
在bin.py導入main.py使用的是這樣的語句:from my_module import main
在main.py導入cal.py應該使用的是這樣的語句:from my_module import cal,這裏面雖然main.py和cal.py同級,可是直接用import cal會報錯,由於系統只認bin.py(執行文件)所在的路徑,而無論main.py和cal.py是否同級
多級路徑狀況下,使用點.來表示層級,舉例:
bin.py--
web--web1--web3--__init.py
--cal.py
from web.web1.web3 import cal from web.web1.web3.cal import add #能夠直接使用add(2,6)
錯誤示例:
from web.web1 import web3 #執行web3的__init__文件, print(web3.cal.add(2,6)) #執行會報錯,惟一不支持的調用方式
解決上面錯誤示例的方法:在web3文件夾的__init__.py裏面加入
from . import cal
則會正確執行 web3.cal.add(2,6)
提示:若是咱們的自定義模塊和Python裏的模塊重名,因爲在sys.path裏面咱們執行文件的路徑在前,Python庫的路徑在後,首先會搜索執行文件的路徑,這樣就會把自定義模塊導入而不會繼續向後搜索系統模塊。
修改路徑的方法和實效
臨時修改:
import sys sys.path.append()
永久修改:
windows:系統屬性--高級--環境變量--系統變量--Path
在工程上的實際應用中目錄結構以下,通常bin是執行的起點:
fatherdir--bin--bin.py
--my_module--main.py
import sys,os BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) sys.path.append(BASE_DIR) #經過BASE_DIR獲得整個項目根目錄。能夠適應拷貝到其餘機器運行的狀況,但目錄結構僅限往上一層的狀況
6,相關知識點:__name__系統變量,取值依據其在不一樣的文件裏而定
1,在執行文件其值爲字符串:__main__
2,在被調用文件其值爲:該文件的路徑,例如:web.web1.web3.cal
使用方法 if __name__=='__main__'
1,在調用文件裏使用,後面是測試代碼。這樣被其餘文件調用的時候這些測試代碼不會執行。
2,在執行文件裏使用,就是不想讓這個文件成爲其餘文件調用的對象。好比這種狀況,這個執行文件裏的函數須要被其餘人調用,其餘人引用這個文件,使用其中某個具體的函數。若是沒有這句話,則會把不須要執行的部分也執行一遍。
二,Python內置模塊
(一)time模塊
import time #時間戳,從1970年UNIX誕生到如今的秒數,作計算使用 print(time.time()) #1481321748.481654秒 #輸出:1549155273.7783637 #當前時間戳的結構化時間---當地時間 print(time.localtime(1549152782)) #輸出:time.struct_time(tm_year=2019, tm_mon=2, tm_mday=3, tm_hour=8, tm_min=13, tm_sec=2, tm_wday=6, tm_yday=34, tm_isdst=0) t=time.localtime() print(t.tm_year) #輸出:2019 print(t.tm_wday) #輸出:6 #當前時間戳的結構化時間---UTC格林尼治 print(time.gmtime()) #輸出:time.struct_time(tm_year=2019, tm_mon=2, tm_mday=3, tm_hour=0, tm_min=54, tm_sec=33, tm_wday=6, tm_yday=34, tm_isdst=0) #結構化時間轉換成時間戳 print(time.mktime(time.localtime())) #輸出:1549155273.0 #結構化時間轉成字符串時間strftime print(time.strftime('%Y---%m-%d %X',time.localtime())) #輸出:2019---02-03 08:54:33 #字符串時間轉成結構化時間strptime print(time.strptime("2016:12:24:17:50:36","%Y:%m:%d:%X")) #輸出:time.struct_time(tm_year=2016, tm_mon=12, tm_mday=24, tm_hour=17, tm_min=50, tm_sec=36, tm_wday=5, tm_yday=359, tm_isdst=-1) #省事的方法直接使用asctime和ctime,可是格式是固定的,如:Sun Feb 3 08:48:31 2019 print(time.asctime())#asctime是從結構化時間轉換成格式化字符串 #輸出:Sun Feb 3 08:54:33 2019 print(time.ctime()) #ctime是從時間戳轉換成格式化字符串 #輸出:Sun Feb 3 08:54:33 2019 #線程推遲指定時間運行,單位:秒 time.sleep(1) #clock() 時間差 #另一個時間模塊datetime,看起來更直觀一點 import datetime print(datetime.datetime.now()) #輸出:2019-02-03 08:54:34.882426
(二)random模塊
import random #0~1的浮點隨機數 ret=random.random() #輸出:0.11582781711340728 #1~3的整形數,包含3 ret=random.randint(1,3) #輸出:3 #1~3的整形數,不包含3 ret=random.randrange(1,3) #輸出:2 #列表中取值 ret=random.choice([11,22,33,44,55]) #輸出:55 #選擇多個,2表明2個 ret=random.sample([11,22,33,44,55],2) #輸出:[22, 33] #任意範圍浮點數,如1~4 ret=random.uniform(1,4) #輸出:2.792166379341647 #打亂順序 ret=[1,2,3,4,5] random.shuffle(ret) #輸出:[5, 2, 1, 4, 3] print(ret) #產生隨機4位驗證碼,數字字母均可能 def v_code(): ret="" for i in range(4): num=random.randint(0,9) alf=chr(random.randint(65,122)) s=str(random.choice([num,alf])) ret+=s return ret print(v_code()) #輸出:94Ve
(三)os模塊
#當前運行文件的工做目錄 print(os.getcwd()) #輸出:D:\03Study\day22\day22課件代碼 #改變目錄,至關於cd os.chdir("..") #..向上一級目錄,如工做目錄下有名爲「dir1」的目錄能夠寫成os.chdir("dir1") print(os.getcwd()) #輸出:D:\03Study\day22 #返回當前目錄 print(os.curdir) #輸出:. #返回當前目錄的父目錄 print(os.pardir) #輸出:..
#可生成多層遞歸目錄,若是有同名文件夾報錯 os.makedirs('dirname1/dirname2') #若目錄爲空,則刪除,並遞歸到上一級目錄,如若也爲空,則刪除,依次類推。若是目錄有文件報錯 os.removedirs("dirname1/dirname2") #生成單級目錄,至關於shell中的mkdir dirname os.mkdir('dirname') #刪除單極空目錄,若目錄爲不爲空則沒法刪除,報錯,至關於shell中的rmdir dirname os.rmdir('dirname') #列出指定目錄下的全部文件和子目錄,包括隱藏文件,並以列表方式打印 print(os.listdir()) #輸出:['json&pickle.py', 'newname', 'os_test.py', 'output.xml', 're_lesson.py', 'sys_test.py', 'test.xml', 'xml_lesson', 'xml_test.py', '__init__.py', '序列化對象_pickle'] #刪除一個文件 os.remove('dirname/we') #重命名文件/目錄 os.rename('dirname','newname') #獲取文件/目錄信息 print(os.stat("newname/we")) #輸出:os.stat_result(st_mode=33206, st_ino=10977524091731226, st_dev=1692480672, st_nlink=1, st_uid=0, st_gid=0, st_size=0, st_atime=1549285018, st_mtime=1549285018, st_ctime=1549285018)
#操做系統特定的路徑分隔符,win下爲‘\\’,Linux下爲‘/’ print(os.sep) #當前平臺使用的行終止符,win下爲‘\r\n’,Linux下爲'\n' print(os.linesep) #用於分割文件路徑的字符串win下爲;Linux下爲:。好比在path系統環境變量裏面分割項與項 print(os.pathsep) #輸出字符串只是當前使用平臺,win下爲'nt',Linux爲'posix' print(os.name) #終端執行shell命令 print(os.system("dir")) #獲取系統環境變量 print(os.environ) #輸出:environ({'PATH': 'D:\\03Study\\venv\\Scripts;D:\\Python35\\Scripts\\;D:\\Python35\\;D:\\Python27\\;D:\\Python27\\Scripts;C:\\Windows\\system32;C:\\Windows;C:\\Windows\\System32\\Wbem;C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\;D:\\Program Files (x86)\\Rational\\common;D:\\Program Files (x86)\\Rational\\Common', 'PROMPT': '(venv) $P$G', 'NUMBER_OF_PROCESSORS': '2', 'PROCESSOR_ARCHITECTURE': 'AMD64', 'HOMEDRIVE': 'C:', 'USERPROFILE': 'C:\\Users\\fudonghai', 'COMMONPROGRAMFILES': 'C:\\Program Files\\Common Files', 'PROCESSOR_IDENTIFIER': 'Intel64 Family 6 Model 15 Stepping 13, GenuineIntel', 'ONEDRIVE': 'D:\\OneDrive', 'PYTHONUNBUFFERED': '1', 'LOCALAPPDATA': 'C:\\Users\\fudonghai\\AppData\\Local', 'APPDATA': 'C:\\Users\\fudonghai\\AppData\\Roaming', '_OLD_VIRTUAL_PATH': 'D:\\Python35\\Scripts\\;D:\\Python35\\;D:\\Python27\\;D:\\Python27\\Scripts;C:\\Windows\\system32;C:\\Windows;C:\\Windows\\System32\\Wbem;C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\;D:\\Program Files (x86)\\Rational\\common;D:\\Program Files (x86)\\Rational\\Common', 'WINDOWS_TRACING_FLAGS': '3', 'PROCESSOR_LEVEL': '6', 'TMP': 'C:\\Users\\FUDONG~1\\AppData\\Local\\Temp', '_OLD_VIRTUAL_PROMPT': '$P$G', 'PYCHARM_MATPLOTLIB_PORT': '49323', 'SYSTEMDRIVE': 'C:', 'HOMEPATH': '\\Users\\fudonghai', 'COMPUTERNAME': 'FUDONGHAI-NOTE', 'FP_NO_HOST_CHECK': 'NO', 'PROCESSOR_REVISION': '0f0d', 'SESSIONNAME': 'Console', 'PROGRAMFILES(X86)': 'C:\\Program Files (x86)', 'WINDIR': 'C:\\Windows', 'USERDOMAIN': 'fudonghai-Note', 'USERNAME': 'fudonghai', 'PYCHARM_HOSTED': '1', 'TEMP': 'C:\\Users\\FUDONG~1\\AppData\\Local\\Temp', 'PROGRAMDATA': 'C:\\ProgramData', 'PYTHONPATH': 'D:\\03Study;C:\\Program Files\\JetBrains\\PyCharm 2018.3.3\\helpers\\pycharm_matplotlib_backend', 'WINDOWS_TRACING_LOGFILE': 'C:\\BVTBin\\Tests\\installpackage\\csilogfile.log', 'VIRTUAL_ENV': 'D:\\03Study\\venv', 'PYTHONIOENCODING': 'UTF-8', 'PROGRAMFILES': 'C:\\Program Files', 'ALLUSERSPROFILE': 'C:\\ProgramData', 'SYSTEMROOT': 'C:\\Windows', '__COMPAT_LAYER': 'DisableUserCallbackException', 'TFS_DIR': 'D:\\Program Files (x86)\\ThinkVantage Fingerprint Software\\', 'LOGONSERVER': '\\\\FUDONGHAI-NOTE', 'OS': 'Windows_NT', 'PROGRAMW6432': 'C:\\Program Files', 'PSMODULEPATH': 'C:\\Windows\\system32\\WindowsPowerShell\\v1.0\\Modules\\;C:\\Program Files\\Intel\\', 'PUBLIC': 'C:\\Users\\Public', 'PATHEXT': '.COM;.EXE;.BAT;.CMD;.VBS;.VBE;.JS;.JSE;.WSF;.WSH;.MSC;.PY;.PYW', 'COMMONPROGRAMW6432': 'C:\\Program Files\\Common Files', 'COMSPEC': 'C:\\Windows\\system32\\cmd.exe', 'COMMONPROGRAMFILES(X86)': 'C:\\Program Files (x86)\\Common Files', 'PYCHARM': 'C:\\Program Files\\JetBrains\\PyCharm 2018.3.3\\bin;'}) #把path分割成目錄和文件名二元組返回 print(os.path.split(r"C:\Users\Administrator\脫產三期\day22\sss.py")) #輸出:('C:\\Users\\Administrator\\脫產三期\\day22', 'sss.py') #返回path的目錄,其實就是os.path.split的第一個元素 print(os.path.dirname(r"C:\Users\Administrator\脫產三期\day22\sss.py")) #輸出:C:\Users\Administrator\脫產三期\day22 #返回path最後的文件名,如path以/或者\結尾,那麼就會返回空值。即os.path.split的第二個元素 print(os.path.basename(r"C:\Users\Administrator\脫產三期\day22\sss.py")) #輸出:sss.py #若是path存在,返回True;若是不存在,返回False print(os.path.exists('D:\\03Study\day22\\day22課件代碼\\newname')) #輸出:True #路徑拼接 a="C:\\Users\\Administrator" b="脫產三期\\day22\\sss.py" print(os.path.join(a,b)) #輸出:C:\Users\Administrator\脫產三期\day22\sss.py
#和文件時間相關的函數,原來上面講過stat能夠看到三個時間 print(os.stat("newname/we")) #st_atime=1549375382, st_mtime=1549375382, st_ctime=1549285018 #返回path所指向的文件或者目錄的最後存取時間 print(os.path.getatime("newname/we")) #輸出:1549375382.7303739 #返回path所指向的文件或者目錄的最後修改時間 print(os.path.getmtime("newname/we")) #輸出:1549375382.731374 #返回path所指向的文件或者目錄的創建時間 print(os.path.getctime("newname/we")) #輸出:1549285018.1002722
(四)sys模塊
import sys #命令行參數List,用於在程序初始化時接受參數,第一個元素是程序自己文件名 #在終端裏面輸入:python sys_test.py post D:/03Study/day22/day22課件代碼/sys_test.py print(sys.argv) command=sys.argv[1] path=sys.argv[2] if command=="post": print('post') elif command=="get": print('get') '''輸出: ['sys_test.py', 'post', 'D:/03Study/day22/day22課件代碼/sys_test.py'] post ''' #獲取Python解釋程序的版本信息 print(sys.version) #獲取最大的Int值 print(sys.maxsize) #輸出:9223372036854775807 #返回模塊的搜素路徑,初始化時使用PYTHONPATH環境變量的值 print(sys.path) #輸出:['D:\\03Study\\day22\\day22課件代碼', 'D:\\03Study', 'D:\\03Study\\venv\\Scripts\\python35.zip', 'D:\\Python35\\DLLs', 'D:\\Python35\\lib', 'D:\\Python35', 'D:\\03Study\\venv', 'D:\\03Study\\venv\\lib\\site-packages', 'D:\\03Study\\venv\\lib\\site-packages\\setuptools-39.1.0-py3.5.egg', 'D:\\03Study\\venv\\lib\\site-packages\\pip-10.0.1-py3.5.egg', 'C:\\Program Files\\JetBrains\\PyCharm 2018.3.3\\helpers\\pycharm_matplotlib_backend'] #獲取操做系統平臺名稱 print(sys.platform) #輸出:win32 #進度條功能sys.stdout import time for i in range(100): sys.stdout.write("#") time.sleep(0.1) sys.stdout.flush() #輸出進度條 #退出程序,正常退出時exit(0) sys.exit(1) #輸出:Process finished with exit code 1
(五)json & pickle 模塊
import json #json.dumps會把全部的單引號變成雙引號,再把數據變成json字符串 dic={'name':'alex'}#---->{"name":"alex"}----->'{"name":"alex"}' i=8 #---->'8' s='hello' #---->"hello"------>'"hello"' l=[11,22] #---->"[11,22]" f=open("new_hello","w") dic_str=json.dumps(dic) f.write(dic_str) #上面兩句等效一句:json.dump(dic,f),注意這個dump沒有s f.close() #json.loads把字符串還原成原數據格式 f_read=open("new_hello","r") data=json.loads(f_read.read()) #上面兩句等效一句:data=json.load(f),注意這個load沒有s print(data) print(type(data)) #輸出:{'name': 'alex'} #輸出:<class 'dict'> #注意:loads前不是必須dump,只要符合json字符串的格式,能夠直接loads import json with open("Json_test","r") as f: data=f.read() data=json.loads(data) print(data["name"])
pickle模塊比json模塊能處理更多的數據類型,可是對人來講可讀性很差,因此使用範圍並無json普遍。
序列化:把對象從內存中變成可存儲或傳輸的過程稱之爲序列化,在Python中叫pickling,序列化以後,就能夠把序列化以後的內容寫入磁盤,或者經過網絡傳輸到別的機器上。
反序列化:把變量的內容從序列化的對象從新讀取到內存裏稱之爲反序列化,即unpickling。
import pickle dic = {'name': 'alvin', 'age': 23, 'sex': 'male'} print(type(dic)) #<class 'dict'> # --------序列化 j = pickle.dumps(dic) print(type(j)) #<class 'bytes'> f = open('序列化對象_pickle', 'wb') #注意是w是寫入str,wb是寫入bytes,j是'bytes' f.write(j) #等價於pickle.dump(dic,f) f.close() # --------反序列化 f = open('序列化對象_pickle', 'rb') data = pickle.loads(f.read()) # 等價於data=pickle.load(f) print(data['age']) #輸出:23
(六)shelve模塊
shelve模塊把全部操做都變成字典。 會生成三個文件,後綴爲bak,dat,dir
import shelve f = shelve.open(r'shelve1') # 目的:將一個字典放入文本 f={} f['stu1_info']={'name':'alex','age':'18'} f['stu2_info']={'name':'alvin','age':'20'} f['school_info']={'website':'oldboyedu.com','city':'beijing'} f.close() # print(f.get('stu1_info')['age']) # print(f.get('school_info')['website']) '''輸出: 18 oldboyedu.com '''
(七)xml模塊
xml比json早,在不少領域已經使用,不容易替換。
import xml.etree.ElementTree as ET #解析xml文件,獲得文檔樹 tree = ET.parse("xml_lesson") #獲得根節點 root = tree.getroot() #打印tag即爲xml標籤 print(root.tag) #輸出:data for i in root: #標籤名字 print(i.tag) #屬性 print(i.attrib) for j in i: #print(j.tag) #print(j.attrib) #內容 print(j.text) '''輸出: data country {'add': 'yes', 'name': 'Liechtenstein'} 2 2010 141100 None None country {'name': 'Singapore'} 5 2013 59900 None country {'name': 'Panama'} 69 2013 13600 None None ''' # 遍歷xml文檔 for child in root: print(child.tag, child.attrib) for i in child: print(i.tag, i.text) 只遍歷標籤爲year的節點 for node in root.iter('year'): print(node.tag, node.text) '''輸出: year 2010 year 2013 year 2013 ''' # 修改 for node in root.iter('year'): new_year = int(node.text) + 1 node.text = str(new_year) node.set("updated", "yes") #寫入文件纔會生效 tree.write("xml_lesson") # 刪除node for country in root.findall('country'): rank = int(country.find('rank').text) if rank > 4: root.remove(country) tree.write('output.xml') #建立XML文件 new_xml = ET.Element("namelist") #建立根節點 #new_xml:處理對象,name:標籤,attrib:屬性 name = ET.SubElement(new_xml, "name", attrib={"enrolled": "yes"}) age = ET.SubElement(name, "age", attrib={"checked": "no"}) sex = ET.SubElement(name, "sex") sex.text = '33' name2 = ET.SubElement(new_xml, "name", attrib={"enrolled": "no"}) age = ET.SubElement(name2, "age") age.text = '19' #生成文檔對象 et = ET.ElementTree(new_xml) et.write("test.xml", encoding="utf-8", xml_declaration=True) #ET.dump(new_xml) # 打印生成的格式 '''輸出:test.xml <?xml version='1.0' encoding='utf-8'?> <namelist> <name enrolled="yes"> <age checked="no" /> <sex>33</sex> </name> <name enrolled="no"> <age>19</age> </name> </namelist> '''
(八)logging模塊
1,默認狀況下Python的logging模塊將日誌打印到了標準輸出中,且只顯示了大於等於WARNING級別的日誌,這說明默認的日誌級別設置爲WARNING(日誌級別等級CRITICAL > ERROR > WARNING > INFO > DEBUG > NOTSET),默認的日誌格式爲日誌級別:Logger名稱:用戶輸出消息。
通常調試程序使用DEBUG輸出大量日誌信息,而生產環境使用WARNING往上減小無用信息
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 '''
2,使用logging.basicConfig()進行初步配置,缺點是隻能在屏幕或者文件擇其一輸出
logging.basicConfig( level=logging.DEBUG, #設置輸出級別 filename="loger.log", #輸出到文件而不是到標準輸出,默認採用追加模式 filemode="w", #把模式改成清空重寫模式 format='%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s', # 時間 源文件名 [line:源文件行號] 級別 信息 datefmt='%a, %d %b %Y %H:%M:%S', #Wed, 13 Feb 2019 11:17:38 ) logging.debug('debug message') logging.info('info message') logging.warning('warning message') logging.error('error message') logging.critical('critical message') '''輸出: Wed, 13 Feb 2019 11:17:38 s1.py[line:12] DEBUG debug message Wed, 13 Feb 2019 11:17:38 s1.py[line:13] INFO info message Wed, 13 Feb 2019 11:17:38 s1.py[line:14] WARNING warning message Wed, 13 Feb 2019 11:17:38 s1.py[line:15] ERROR error message Wed, 13 Feb 2019 11:17:38 s1.py[line:16] CRITICAL critical message '''
可見在logging.basicConfig()函數中可經過具體參數來更改logging模塊默認行爲,可用參數有
filename:用指定的文件名建立FiledHandler(後邊會具體講解handler的概念),這樣日誌會被存儲在指定的文件中。
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用戶輸出的消息
3,logger對象:能夠在屏幕和文件同時輸出
例子一:
Logger是一個樹形層級結構,輸出信息以前都要得到一個Logger(若是沒有顯示的獲取則自動建立並使用root Logger,如第一個例子所示)。
logger = logging.getLogger()返回一個默認的Logger也即root Logger,並應用默認的日誌級別、Handler和Formatter設置。
固然也能夠經過Logger.setLevel(lel)指定最低的日誌級別,可用的日誌級別有"DEBUG"、"INFO"、"WARNING"、"ERROR"、"CRITICAL"。
最後使用Logger.debug()、Logger.info()、Logger.warning()、Logger.error()、Logger.critical()輸出不一樣級別的日誌,只有日誌等級大於或等於設置的日誌級別的日誌纔會被輸出。
通常來講
def logger(): #建立logger對象 logger=logging.getLogger() #建立向文件裏發送內容fh句柄 fh=logging.FileHandler("test_log") #建立向屏幕裏發送內容ch句柄 ch=logging.StreamHandler() #添加句柄操做 logger.addHandler(fh) logger.addHandler(ch) #日誌格式設定 fm=logging.Formatter("%(asctime)s %(message)s") #格式生效 fh.setFormatter(fm) ch.setFormatter(fm) #日誌級別 logger.setLevel("DEBUG") #返回對象 return logger #能夠在任意一個py文件使用這個對象打印 ret=logger() ret.debug("hello debug") ret.info("hello info") '''輸出:文件和屏幕都會出現 2019-02-13 11:36:44,483 hello debug 2019-02-13 11:36:44,485 hello info '''
logging庫提供了多個組件:Logger、Handler、Filter、Formatter。Logger對象提供應用程序可直接使用的接口,Handler發送日誌到適當的目的地,Filter提供了過濾日誌信息的方法,Formatter指定日誌顯示格式。
例子二:兩個logger對象
logger=logging.getLogger() logger1 = logging.getLogger('mylogger') logger1.setLevel(logging.DEBUG) logger2 = logging.getLogger('mylogger') logger2.setLevel(logging.WARNING) fh=logging.FileHandler("test_log-new") ch=logging.StreamHandler() logger.addHandler(ch) logger.addHandler(fh) logger1.addHandler(fh) logger1.addHandler(ch) logger2.addHandler(fh) logger2.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') '''輸出:logger1和logger2每一個出現兩次 logger warning message logger error message logger critical message logger1 warning message logger1 warning message logger1 error message logger1 error message logger1 critical message logger1 critical message logger2 warning message logger2 warning message logger2 error message logger2 error message logger2 critical message logger2 critical message '''
這裏有兩個問題:
<1>咱們明明經過logger1.setLevel(logging.DEBUG)將logger1的日誌級別設置爲了DEBUG,爲什麼顯示的時候沒有顯示出DEBUG級別的日誌信息,而是從WARNING級別的日誌開始顯示呢?
原來logger1和logger2對應的是同一個Logger實例,只要logging.getLogger(name)中名稱參數name相同則返回的Logger實例就是同一個,且僅有一個,也即name與Logger實例一一對應。在logger2實例中經過logger2.setLevel(logging.WARNING)設置mylogger的日誌級別爲logging.WARNING,因此最後logger1的輸出聽從了後來設置的日誌級別。個人理解就是隻存在兩個對象默認的root根logger和兒子logger:logger1
<2>爲何logger一、logger2對應的每一個輸出分別顯示兩次?
這是由於咱們經過logger = logging.getLogger()顯示的建立了root Logger,而logger1 = logging.getLogger('mylogger')建立了root Logger的孩子(root.)mylogger,logger2一樣。而孩子,孫子,重孫……既會將消息分發給他的handler進行處理也會傳遞給全部的祖先Logger處理。
ok,那麼如今咱們把
# logger.addHandler(fh)
# logger.addHandler(ch) 註釋掉,咱們再來看效果:
'''輸出:logger1和logger2只出現一次 logger warning message logger error message logger critical message logger1 warning message logger1 error message logger1 critical message logger2 warning message logger2 error message logger2 critical message '''
由於咱們註釋了logger對象顯示的位置,因此才用了默認方式,即標準輸出方式。由於它的父級沒有設置文件顯示方式,因此在這裏只打印了一次。
孩子,孫子,重孫……可逐層繼承來自祖先的日誌級別、Handler、Filter設置,也能夠經過Logger.setLevel(lel)、Logger.addHandler(hdlr)、Logger.removeHandler(hdlr)、Logger.addFilter(filt)、Logger.removeFilter(filt)。設置本身特別的日誌級別、Handler、Filter。若不設置則使用繼承來的值。
例子三:filter的使用限制只有知足過濾規則的日誌纔會輸出。
好比咱們定義了filter = logging.Filter('a.b.c'),並將這個Filter添加到了一個Handler上,則使用該Handler的Logger中只有名字帶a.b.c前綴的Logger才能輸出其日誌。
import logging def logger(): #建立logger對象 logger=logging.getLogger() #建立向文件裏發送內容fh句柄 fh=logging.FileHandler("test_log") #建立向屏幕裏發送內容ch句柄 ch=logging.StreamHandler() #添加句柄操做 logger.addHandler(fh) logger.addHandler(ch) #日誌格式設定 fm=logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s') #格式生效 fh.setFormatter(fm) ch.setFormatter(fm) # 定義一個filter filter = logging.Filter('mylogger') fh.addFilter(filter) ch.addFilter(filter) #日誌級別 logger.setLevel("DEBUG") #返回對象 return logger #能夠在任意一個py文件使用這個對象打印 ret=logger() ret.debug("hello debug") ret.info("hello info") '''輸出: 若是filter設置爲"root"則 2019-02-13 19:47:49,003 - root - DEBUG - hello debug 2019-02-13 19:47:49,004 - root - INFO - hello info 若是filter設置爲"mylogger"則沒有輸出 '''
(九)configparser模塊:寫配置文件
1,建立一個配置文件
import configparser #調用ConfigParser()實例化一個對象,就有了一個空字典 config = configparser.ConfigParser() #config={} #寫法1,頂級鍵"DEFAULT" config["DEFAULT"] = {'ServerAliveInterval': '45', 'Compression': 'yes', 'CompressionLevel': '9'} #寫法2,頂級鍵'bitbucket.org' config['bitbucket.org'] = {} config['bitbucket.org']['User'] = 'hg' #寫法3,頂級鍵'topsecret.server.com' config['topsecret.server.com'] = {} topsecret = config['topsecret.server.com'] topsecret['Host Port'] = '50022' # mutates the parser topsecret['ForwardX11'] = 'no' # same here #把對象寫入文件 with open('example.ini', 'w') as f: config.write(f) '''輸出:example.ini [DEFAULT] serveraliveinterval = 45 compression = yes compressionlevel = 9 [bitbucket.org] user = hg [topsecret.server.com] host port = 50022 forwardx11 = no '''
2,查example.ini
import configparser #調用ConfigParser()實例化一個對象,就有了一個空字典 config = configparser.ConfigParser() #config={} config.read('example.ini') #sections()方法輸出除了[DEFAULT]之外的頂級鍵 print(config.sections()) #輸出:['bitbucket.org', 'topsecret.server.com'] #用來判斷'bytebong.com'是不是頂級鍵 print('bytebong.com' in config) # 輸出:False #輸出鍵的值 print(config['bitbucket.org']['User']) #輸出:hg print(config['DEFAULT']['Compression']) #輸出:yes print(config['topsecret.server.com']['ForwardX11']) #若是鍵名錯誤則程序報錯 #輸出:no #遍歷頂級鍵下的鍵,把DEFAULT的也會輸出 #因此DEFAULT裏面必定放公共信息,這樣其它鍵都能讀取 for key in config['topsecret.server.com']: print(key) '''輸出: host port forwardx11 serveraliveinterval compression compressionlevel ''' #options功能是取鍵 print(config.options('bitbucket.org')) #輸出:['user', 'serveraliveinterval', 'compression', 'compressionlevel', 'forwardx11'] #items取鍵和值 print(config.items('bitbucket.org')) #輸出:[('serveraliveinterval', '45'), ('compression', 'yes'), ('compressionlevel', '9'), ('forwardx11', 'yes'), ('user', 'hg')] #get能夠連續放入鍵及其子鍵 print(config.get('bitbucket.org','compression')) #輸出:yes
3,增刪改
import configparser #調用ConfigParser()實例化一個對象,就有了一個空字典 config = configparser.ConfigParser() #config={} config.read('example.ini') #增長頂級鍵yuan config.add_section('yuan') #增長頂級鍵下面的鍵值對 config.set('yuan','k1','11111') #刪除頂級鍵,連同下面的內容所有刪除 config.remove_section('yuan') #刪除頂級鍵下面的鍵值對 config.remove_option('bitbucket.org','user') #寫入才能生效 with open('example.ini', 'w+') as f: config.write(f) #另外一種寫法,不須要close #config.write(open('i.cfg', "w"))
(十)hashlib模塊:hash算法,摘要算法
用於加密相關的操做,3.x裏代替了md5模塊和sha模塊,主要提供 SHA1, SHA224, SHA256, SHA384, SHA512 ,MD5 算法
import hashlib m=hashlib.md5()# m=hashlib.sha256() m.update('hello'.encode('utf8')) print(m.hexdigest()) #5d41402abc4b2a76b9719d911017c592 m.update('alvin'.encode('utf8')) print(m.hexdigest()) #92a7e713c30abbb0319fa07da2a5c4af m2=hashlib.md5() m2.update('helloalvin'.encode('utf8')) print(m2.hexdigest()) #92a7e713c30abbb0319fa07da2a5c4af
上面,先update("hello"),而後update("alvin")的結果和直接update("helloalvin")同樣
以上加密算法雖然依然很是厲害,但時候存在缺陷,即:經過撞庫能夠反解。因此,有必要對加密算法中添加自定義key再來作加密。
import hashlib obj = hashlib.md5("private".encode('utf-8'))#括號裏面的稱爲「鹽」 obj.update("hello".encode("utf-8")) print(obj.hexdigest()) #沒有加鹽:5d41402abc4b2a76b9719d911017c592 #加鹽後 :fc820a1cfa3dc4e81efb96c61fe9b981
SHA256算法和MD5算法的用法是同樣的,堅固程度好一點
import hashlib # ######## 256 ######## hash = hashlib.sha256('898oaFs09f'.encode('utf8')) hash.update('alvin'.encode('utf8')) print (hash.hexdigest())#e79e68f070cdedcfe63eaf1a2e92c83b4cfb1b5c6bc452d214c1b7e77cdfd1c7