Python學習--day17
阿新 • • 發佈:2018-12-07
day17
一、logging模組
1、日誌中的級別:
import logging # logging.debug("debug") #日誌等級10級 # logging.info("info") #日誌等級20級 # logging.warning("警告warn") #日誌等級30級(預設起始列印級別) # logging.error("錯誤error") #日誌等級40級 # logging.critical("嚴重critical") #日誌等級50級 # result: # WARNING:root:警告warn# ERROR:root:錯誤error # CRITICAL:root:嚴重critical 預設的輸出位置是控制檯,預設的最低輸出級別是30級(warning)。
2、如何修改預設配置
可在logging.basicConfig()函式中通過具體引數來更改logging模組預設行為,可用引數有: 1、filename:用指定的檔名建立FiledHandler(後邊會具體講解handler的概念),這樣日誌會被儲存在指定的檔案中。 2、filemode:檔案開啟方式,在指定了filename時使用這個引數,預設值為“a”還可指定為“w”。 3、format:指定handler使用的日誌顯示格式。4、datefmt:指定日期時間格式。 5、level:設定rootlogger(後邊會講解具體概念)的日誌級別 6、stream:用指定的stream建立StreamHandler。可以指定輸出到sys.stderr,sys.stdout或者檔案,預設為7、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:使用者輸出的訊息
手動配置例項:
import logging logging.basicConfig(filename='access.log', format='%(asctime)s - %(name)s - %(levelname)s -%(module)s: %(message)s', datefmt='%Y-%m-%d %H:%M:%S %p', level=10) logging.debug('除錯debug') logging.info('訊息info') logging.warning('警告warn') logging.error('錯誤error') logging.critical('嚴重critical') #result: access.log檔案中內容:(配置中filename='access.log'表示將日誌內容輸出到檔案中 2017-07-28 20:32:17 PM - root - DEBUG -test: 除錯debug 2017-07-28 20:32:17 PM - root - INFO -test: 訊息info 2017-07-28 20:32:17 PM - root - WARNING -test: 警告warn 2017-07-28 20:32:17 PM - root - ERROR -test: 錯誤error 2017-07-28 20:32:17 PM - root - CRITICAL -test: 嚴重critical
3、logging模組的4個核心角色
import logging #1、logger物件:負責產生日誌,然後交給Filter過濾,然後交給不同的Handler輸出 logger=logging.getLogger(__file__) # 注:因為logger物件也可以為日誌設定過濾等級,所以一般直接用 # logger.setLevel(10) 設定輸出等級 #2、Filter物件:不常用,略 #3、Handler物件:接收logger傳來的日誌,然後控制輸出 h1=logging.FileHandler('t1.log') #列印到檔案 h2=logging.FileHandler('t2.log') #列印到檔案 h3=logging.StreamHandler() #列印到終端 #4、Formatter物件:日誌格式(為handler提供列印格式) formmater1=logging.Formatter('%(asctime)s - %(name)s - %(levelname)s -%(module)s: %(message)s', datefmt='%Y-%m-%d %H:%M:%S %p',) formmater2=logging.Formatter('%(asctime)s : %(message)s', datefmt='%Y-%m-%d %H:%M:%S %p',) formmater3=logging.Formatter('%(name)s %(message)s',) #5、為Handler物件繫結格式 h1.setFormatter(formmater1) h2.setFormatter(formmater2) h3.setFormatter(formmater3) #6、將Handler新增給logger並設定日誌級別 logger.addHandler(h1) logger.addHandler(h2) logger.addHandler(h3) logger.setLevel(10) #7、測試 logger.debug('debug') logger.info('info') logger.warning('warning') logger.error('error') logger.critical('critical') #注:logger和handler都可以設定過濾級別,但logger是第一級過濾,然後才能到handler
4、用字典配置logger
""" logging配置 """ import os import logging.config # 定義三種日誌輸出格式 開始 standard_format = '[%(asctime)s][%(threadName)s:%(thread)d][task_id:%(name)s][%(filename)s:%(lineno)d]' \ '[%(levelname)s][%(message)s]' #其中name為getlogger指定的名字 simple_format = '[%(levelname)s][%(asctime)s][%(filename)s:%(lineno)d]%(message)s' id_simple_format = '[%(levelname)s][%(asctime)s] %(message)s' # 定義日誌輸出格式 結束 logfile_dir = os.path.dirname(os.path.abspath(__file__)) # log檔案的目錄 logfile_name = 'all2.log' # log檔名 # 如果不存在定義的日誌目錄就建立一個 if not os.path.isdir(logfile_dir): os.mkdir(logfile_dir) # log檔案的全路徑 logfile_path = os.path.join(logfile_dir, logfile_name) # log配置字典 LOGGING_DIC = { 'version': 1, 'disable_existing_loggers': False, 'formatters': { #日誌列印格式 'standard': { 'format': standard_format }, 'simple': { 'format': simple_format }, }, 'filters': {}, #一般不常用 此處不寫 'handlers': { #列印到終端的日誌 'console': { 'level': 'DEBUG', 'class': 'logging.StreamHandler', # 列印到螢幕 'formatter': 'simple' }, #列印到檔案的日誌,收集info及以上的日誌 'default': { 'level': 'DEBUG', 'class': 'logging.handlers.RotatingFileHandler', # 儲存到檔案 'formatter': 'standard', 'filename': logfile_path, # 日誌檔案 'maxBytes': 1024*1024*5, # 日誌大小 5M 'backupCount': 5, #日誌最多隻能儲存5份 超過後自動刪除最老的日誌 'encoding': 'utf-8', # 日誌檔案的編碼,再也不用擔心中文log亂碼了 }, }, 'loggers': { #logging.getLogger(__name__)拿到的logger配置 '': {# key 為空則為預設配置 'handlers': ['default', 'console'], # 這裡把上面定義的兩個handler都加上,即log資料既寫入檔案又列印到螢幕 'level': 'DEBUG', 'propagate': True, # 向上(更高level(父級)的logger)傳遞 }, }, } def load_my_logging_cfg(): logging.config.dictConfig(LOGGING_DIC) # 匯入上面字典中定義的logging配置 logger = logging.getLogger(__name__) # 生成一個log例項 logger.info('It works!') # 記錄該檔案的執行狀態 if __name__ == '__main__': load_my_logging_cfg() """ MyLogging Test """ import time import logging import my_logging # 匯入自定義的logging配置 logger = logging.getLogger(__name__) # 生成logger例項 def demo(): logger.debug("start range... time:{}".format(time.time())) logger.info("中文測試開始。。。") for i in range(10): logger.debug("i:{}".format(i)) time.sleep(0.2) else: logger.debug("over range... time:{}".format(time.time())) logger.info("中文測試結束。。。") if __name__ == "__main__": my_logging.load_my_logging_cfg() # 在你程式檔案的入口載入自定義logging配置 demo()
注意: #1、有了上述方式我們的好處是:所有與logging模組有關的配置都寫到字典中就可以了,更加清晰,方便管理 #2、我們需要解決的問題是: 1、從字典載入配置:logging.config.dictConfig(settings.LOGGING_DIC) 2、拿到logger物件來產生日誌 logger物件都是配置到字典的loggers 鍵對應的子字典中的 按照我們對logging模組的理解,要想獲取某個東西都是通過名字,也就是key來獲取的 於是我們要獲取不同的logger物件就是 logger=logging.getLogger('loggers子字典的key名') 但問題是:如果我們想要不同logger名的logger物件都共用一段配置,那麼肯定不能在loggers子字典中定義n個key 'loggers': { 'l1': { 'handlers': ['default', 'console'], # 'level': 'DEBUG', 'propagate': True, # 向上(更高level的logger)傳遞 }, 'l2: { 'handlers': ['default', 'console' ], 'level': 'DEBUG', 'propagate': False, # 向上(更高level的logger)傳遞 }, 'l3': { 'handlers': ['default', 'console'], # 'level': 'DEBUG', 'propagate': True, # 向上(更高level的logger)傳遞 }, } #我們的解決方式是,定義一個空的key 'loggers': { '': { 'handlers': ['default', 'console'], 'level': 'DEBUG', 'propagate': True, }, } 這樣我們再取logger物件時 logging.getLogger(__name__),不同的檔案__name__不同,這保證了列印日誌時標識資訊不同,但是拿著該名字去loggers裡找key名時卻發現找不到,於是預設使用key=''的配置
5、日誌中的繼承問題
# 定義四種核心角色 import logging mylog = logging.getLogger("father") #按預設配置定義一個新日誌生成器 mylog.setLevel(10) #重新設定列印等級 handler = logging.FileHandler("father.log") #定義控制輸出檔案路徑 mylog.addHandler(handler) #將控制檯繫結給日誌生成器 handler.setLevel(10) #給handler設定日誌輸出等級 fmter = logging.Formatter(fmt="%(threadName)s %(funcName)s %(module)s %(filename)s %(levelname)s %(asctime)s %(message)s") #formatter 自定義日誌輸出格式 handler.setFormatter(fmter) #將自定義的格式繫結給handler # 在獲取一個生成器 同時指定該生成器的父生成器是father這個生成器 sonlog = logging.getLogger("father.son") #定義一個子日誌(通過.來表示繼承) #通過將propagate設定為Ture,使得此日誌中輸出的內容也會傳送一份到他的父生成器中 # 注意:輸出格式還是按照父生成器繫結的格式進行輸出 # 需求:子生成器的輸出位置與父生成器不同 格式相同 sonhandler = logging.FileHandler("son.txt",encoding="utf8") #為子生成器重新定義一個輸出位置(通過控制檯進行定義) sonlog.addHandler(sonhandler) #將定義的handler新增繫結到日誌生成器 sonfmt = logging.Formatter(fmt="%(threadName)s %(funcName)s %(module)s %(filename)s %(levelname)s %(asctime)s %(message)s") #定義輸出格式 sonhandler.setFormatter(sonfmt) # 繼承後子生成器 可以直接使用父生成器的配置 # mylog.info("這是一條日誌資訊!") # sonlog.info("這是 son 輸出的日誌資訊!") #子生成器 在生成一個日誌時 會自動給父生成器也發一個 # 取消傳遞效果 sonlog.propagate = False sonlog.info("這是son輸出的日誌資訊!")
二、shelve模組
shelve模組也是用於序列化羽凡序列化,同pickle模組只能用於Python,不能跨平臺使用。操作簡單,類似Python中的字典。
注: shelve模組比pickle模組簡單,只有一個open函式,返回類似字典的物件,可讀可寫;key必須為字串,而值可以是python所支援的資料型別
import shelve f=shelve.open(r'sheve.txt') # f['stu1_info']={'name':'egon','age':18,'hobby':['piao','smoking','drinking']} # f['stu2_info']={'name':'gangdan','age':53} # f['school_info']={'website':'http://www.pypy.org','city':'beijing'} print(f['stu1_info']['hobby']) f.close()
三、sys模組(系統(Python直譯器系統))
sys模組常用操作方法 1 sys.argv 命令列引數List,第一個元素是程式本身路徑 2 sys.exit(n) 退出程式,正常退出時exit(0) 3 sys.version 獲取Python解釋程式的版本資訊 4 sys.maxint 最大的Int值 5 sys.path 返回模組的搜尋路徑,初始化時使用PYTHONPATH環境變數的值 6 sys.platform 返回作業系統平臺名稱