1. 程式人生 > >Python學習--day17

Python學習--day17

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       返回作業系統平臺名稱