天天看點

19.包 logging 的使用

什麼是包: ---檔案夾下具有__init__.py檔案就是一個包

推薦使用 from . import

包的導入;

  1. from ss.bake.api.policy import func ---絕對導入
  2. from ..api.www import ww ww()---相對路徑導入 必須在外部使用

注意點:

  1. 使用相對路徑必須在最外層報的同級進行導入
  2. python2中import包,如果包沒有__init__.py會報錯,ython3中沒有__init__.py不會報錯

隻要檔案夾下含有__init__.py檔案就是一個包,包是幹什麼的呢?

回想一下,之前我們沒有學習子產品的時候将一個整體的功能寫入到檔案中,為了能夠充分的将某個功能進行重用 我們使用了子產品,但是慢慢的子產品就會越來越多.我們想提高程式的結構性可維護性,就使用包将子產品進行統一管理

包能夠管理多個子產品,我們想要使用包裡的子產品怎麼辦呢?

使用import 和from xx import xx 現有如下結構

bake            

    ├── __init__.py       

    ├── api               

        ├── __init__.py

        ├── policy.py

        └── versions.py

  ├── cmd             

    ├── __init__.py

    └── manage.py

  └── db                

      ├── __init__.py

      └── models.py           

我們在bake同級建立一個test.py進行導入policy.py 我們使用子產品的import的時候隻能将api添加到sys.path的路勁中,我們來看看包使用import導入

import bake.api.policy
bake.api.policy.get()           

導入的太長了下邊使用的時候還需要在重複寫一遍,我們可以使用as起别名

import bake.api.policy as p
p.get()           

這樣的操作隻支援包,普通的檔案夾無效,有人一定在想我把bake拿過來然後一層一層的打開那拿工具就可以了

import bake
bake.api.policy.get()           

不好使,這樣導入是隻将policy導入了,有人想怎麼将api包下的子產品全部導入不要急,先說單獨導入的方式

咱們能夠使用import進行導入,在來看看from的導入方式

from bake.api import policy
policy.get()
from bake import api
print(api.versions.name)           

還是不好使,通過這兩個我們能夠感覺都導入的時候指定要導入的内容,不能再導入後在進行開箱子

我們現在說了單獨導入一個子產品,現在來說道說道怎麼導入某個包下的所有子產品,想要導入某個包下的所有的子產品 我們就需要在包中的__init__.py做點手腳

bake包下的__init__.py
from . import api           

.是目前路徑,因為from的時候不能空着

api包下的__init__.py
from . import policy           

我們将包下的__init__配置好,然後在test.py進行導入

import bake
bake.api.policy.get()           

又好使了,這是為什麼呢?我們import導入bake這個包,因為bake是一個檔案夾不能進行任何操作,就讓__init__.py代替它 去将api這包中的子產品導入,api也是一個檔案夾不能操作就需要讓api下邊的__init__.py去找api下邊的兩個子產品

這個和公司的上下級關系一樣,打比方現在test.py就是一個ceo要和policy這個小員工談話,ceo先把這個想法人事經理,人事經理就是 bake這個包,人事經理通知人事讓人事查找一下policy在那個部門,人事查到後通知部門的負責人,部門的負責人在通知部門的主管,主管告訴policy這個員工, 說ceo要找你,部門的主管帶着policy去找人事,人事帶着policy,人事然後在帶着policy去找ceo.最後成功的和ceo進行了一番交流

如果在傳達的時候中間一個環節忘記傳遞了,policy就不知道ceo在找他,ceo等了好久不來ceo就生氣報錯了

使用的時候需要注意: 有的同學,想在policy檔案中導入versions就是直接使用import,在policy檔案使用沒有問題,很美,很高興.但是在test.py執行的時候就會報錯 因為我們在test.py中執行的import versions 相當于在test.py檔案進行查找,肯定不會找到,我們需要在policy檔案中向sys.path添加了目前的路勁就可以了 具體操作如下:

import os
import sys
sys.path.insert(os.path.dirname(__file__)
           

__file__擷取的是目前檔案的路徑,這樣我們就能在test中正常使用了,我們使用from也能夠将某個包下所有的子產品全都導入 比如我們現在想将cmd包下的所有的子產品導入需要在bake包下的init.py進行設定

from . import *
           

我們需要在api包下設定__init__.py

__all__ = ["policy","versions"]
或
from . import policy
from . import versions
           

我們需要在db包下設定__init__.py

__all__ = ["models"]
或
from . import models
           

我們需要在cmd包下設定__init__.py

__all__ = ["manage"]
或
from . import manage
           

以上兩種推薦使用下from . import manage 靈活,可讀性高

test.py調用如下:

from bake.api import *
print(versions.name)
policy.get()

from bake.db import *
models.register_models(123)

from bake.cmd import *
print(manage.name)
           

在使用import有個注意點,python2中如果import包,沒有__init__.py檔案就會報錯 python3 import沒有__init__.py檔案的包不會報錯 from 包 import 包或者子產品(在import後邊不能在進行.操作)

路徑: 絕對路徑:從最外層(bake)包.查找的就是絕對路徑 相對路徑:.就是相對路徑, ..是上一級目錄 例如:我們在bake/api/version.py中想要導入bake/cmd/manage.py

# 絕對路徑:
from bake.cmd import manage
manage.main()

#相對路徑:
from ..cmd import manage
manage.main()
           

注意在使用相對路徑的時候一定要在于bake同級的檔案中測試 我們需要在和bake同級的test.py中測試

from bake.cmd import manage
           

logging 日志

我們來說一下這個logging子產品,這個子產品的功能是記錄我們軟體的各種狀态,你們現在和我一起找到紅蜘蛛的那個圖示,然後右鍵找一找是不是有個錯誤日志.其實每個軟體都是有錯誤日志的,開發人員可以通過錯誤日志中的内容對他的程式進行修改

這隻是一種應用場景,有的還會将日志用于交易記錄.比如你給我轉賬應該做記錄吧,

我們使用的信用卡,每消費的一筆都會記錄,我們來看看這個日志怎麼用?

我們先來看一下函數式簡單配置

import logging  
logging.debug('debug message')  
logging.info('info message')  
logging.warning('warning message')  
logging.error('error message')  
logging.critical('critical message')
           

預設情況下Python的logging子產品将日志列印到了标準輸出中,且隻顯示了大于等于WARNING級别的日志,這說明預設的日志級别設定為WARNING

(日志級别等級CRITICAL > ERROR > WARNING > INFO > DEBUG),

預設的日志格式為日志級别:Logger名稱:使用者輸出消息。

我們自己用函數寫的這個可以正常使用但是不夠靈活,我們看看這個靈活的

靈活配置日志級别,日志格式,輸出位置:

import logging  
logging.basicConfig(level=logging.DEBUG,  
                    format='%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s',  
                    datefmt='%a, %d %b %Y %H:%M:%S',  
                    filename='test.log',  
                    filemode='w')  

logging.debug('debug message')  
logging.info('info message')  
logging.warning('warning message')  
logging.error('error message')  
logging.critical('critical message')

           

basicConfig()函數中可通過具體參數來更改logging子產品預設行為,可用參數有:

  • filename:用指定的檔案名建立FiledHandler,這樣日志會被存儲在指定的檔案中。
  • filemode:檔案打開方式,在指定了filename時使用這個參數,預設值為“a”還可指定為“w”。
  • format:指定handler使用的日志顯示格式。
  • datefmt:指定日期時間格式。
  • level:設定記錄日志的級别
  • 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對象配置

import logging

logger = logging.getLogger()
# 建立一個handler,用于寫入日志檔案
fh = logging.FileHandler('test.log',mode="a",encoding='utf-8') 

# 再建立一個handler,用于輸出到控制台 
ch = logging.StreamHandler() #螢幕
formatter = logging.Formatter('%(asctime)s - %(name)s - %(filename)s-[line:%(lineno)d]%(levelname)s - %(message)s')#--将螢幕和檔案都用以上格式

fh.setLevel(logging.DEBUG)#設定記錄級别

fh.setFormatter(formatter) 
#  使用自己定義的格式化内容
ch.setFormatter(formatter) 

logger.addHandler(fh) #logger對象可以添加多個fh和ch對象 
logger.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')

           

logging庫提供了多個元件:Logger、Handler、Filter、Formatter。Logger對象提供應用程式可直接使用的接口,Handler發送日志到适當的目的地,Filter提供了過濾日志資訊的方法,Formatter指定日志顯示格式。另外,可以通過:logger.setLevel(logging.Debug)設定級别,當然,也可以通過

fh.setLevel(logging.Debug)單對檔案流設定某個級别。