日志模塊和包
logging
logging模塊簡介
logging模塊是記錄我們軟件的各種狀態,還可以記錄各種交易信息
其實每個軟件都是有錯誤日志的,開發人員可以通過錯誤日志中的內容對他的程序進行修改
日志級別
import logginglogging.debug('調試debug') # DEBUG = 10
logging.info('消息info') # INFO = 20
logging.warning('警告warn') # WARNING = 30
logging.error('錯誤error') # ERROR = 40
logging.critical('嚴重critical') # CRITICAL = 50'''
WARNING:root:警告warn
ERROR:root:錯誤error
CRITICAL:root:嚴重critical
'''
默認情況下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='/tmp/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用戶輸出的消息
logging對象配置
import logginglogger = logging.getLogger()
# 創建一個handler,用于寫入日志文件
fh = logging.FileHandler('test.log',encoding='utf-8') # 再創建一個handler,用于輸出到控制臺
ch = logging.StreamHandler()
formatter = logging.Formatter('%(asctime)s - %(name)s - %(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)單對文件流設置某個級別。
包
包的簡介
包是一種通過使用‘.模塊名’來組織python模塊名稱空間的方式。
具體的:包就是一個包含有__init__.py文件的文件夾,所以其實我們創建包的目的就是為了用文件夾將文件/模塊組織起來
需要強調的是:
- 在python3中,即使包下沒有__init__.py文件,import 包仍然不會報錯,而在python2中,包下一定要有該文件,否則import 包報錯
- 創建包的目的不是為了運行,而是被導入使用,記住,包只是模塊的一種形式而已,包的本質就是一種模塊
為何要使用包
包的本質就是一個文件夾,那么文件夾唯一的功能就是將文件組織起來
隨著功能越寫越多,我們無法將所以功能都放到一個文件中,于是我們使用模塊去組織功能,而隨著模塊越來越多,我們就需要用文件夾將模塊文件組織起來,以此來提高程序的結構性和可維護性
glance/ #Top-level package├── __init__.py #Initialize the glance package├── api #Subpackage for api│ ├── __init__.py│ ├── policy.py│ └── versions.py├── cmd #Subpackage for cmd│ ├── __init__.py│ └── manage.py└── db #Subpackage for db├── __init__.py└── models.py
注意項
#1.關于包相關的導入語句也分為import和from ... import ...兩種,但是無論哪種,無論在什么位置,在導入時都必須遵循一個原則:凡是在導入時帶點的,點的左邊都必須是一個包,否則非法。可以帶有一連串的點,如item.subitem.subsubitem,但都必須遵循這個原則。但對于導入后,在使用時就沒有這種限制了,點的左邊可以是包,模塊,函數,類(它們都可以用點的方式調用自己的屬性)。#2、import導入文件時,產生名稱空間中的名字來源于文件,import 包,產生的名稱空間的名字同樣來源于文件,即包下的__init__.py,導入包本質就是在導入該文件#3、包A和包B下有同名模塊也不會沖突,如A.a與B.a來自倆個命名空間
文件內容
按 Ctrl+C 復制代碼
按 Ctrl+C 復制代碼
執行文件與示范文件在同級目錄下
包的使用之import
import glance.db.models
glance.db.models.register_models('mysql')
單獨導入包名稱時不會導入包中所有包含的所有子模塊,如
#在與glance同級的test.py中
import glance
glance.cmd.manage.main()'''
執行結果:
AttributeError: module 'glance' has no attribute 'cmd''''
解決方法:
#glance/__init__.py
from . import cmd#glance/cmd/__init__.py
from . import manage
執行:
#在于glance同級的test.py中
import glance
glance.cmd.manage.main()
包的使用之from ... import ...
需要注意的是from后import導入的模塊,必須是明確的一個不能帶點,否則會有語法錯誤,如:from a import b.c是錯誤語法
from glance.db import models
models.register_models('mysql')from glance.db.models import register_models
register_models('mysql')
from glance.api import *
在講模塊時,我們已經討論過了從一個模塊內導入所有,此處我們研究從一個包導入所有。
此處是想從包api中導入所有,實際上該語句只會導入包api下__init.py文件中定義的名字,我們可以在這個文件中定義_all:
# 在__init__.py中定義
x=10def func():print('from api.__init.py')__all__=['x','func','policy']
此時我們在于glance同級的文件中執行from glance.api import *就導入__all__中的內容(versions仍然不能導入)。
# 在__init__.py中定義
x = 10def func():print('from api.__init.py')__all__=['x','func','policy']
此時我們在于glance同級的文件中執行from glance.api import *就導入__all__中的內容(versions仍然不能導入)。
練習:
# 執行文件中的使用效果如下,請處理好包的導入
from glance import *get()
create_resource('a.conf')
main()
register_models('mysql')
絕對導入和相對導入
我們的最頂級包glance是寫給別人用的,然后在glance包內部也會有彼此之間互相導入的需求,這時候就有絕對導入和相對導入兩種方式:
絕對導入:以glance作為起始
相對導入:用.或者..的方式最為起始(只能在一個包中使用,不能用于不同目錄內)
例如:我們在glance/api/version.py中想要導入glance/cmd/manage.py
在glance/api/version.py# 絕對導入
from glance.cmd import manage
manage.main()# 相對導入
from ..cmd import manage
manage.main()
測試結果:注意一定要在于glance同級的文件中測試
from glance.api import versions
包以及包所包含的模塊都是用來被導入的,而不是被直接執行的。而環境變量都是以執行文件為準的
比如我們想在glance/api/versions.py中導入glance/api/policy.py,有的同學一抽這倆模塊是在同一個目錄下,十分開心的就去做了,它直接這么做
# 在version.py中import policy
policy.get()
沒錯,我們單獨運行version.py是一點問題沒有的,運行version.py的路徑搜索就是從當前路徑開始的,于是在導入policy時能在當前目錄下找到
但是你想啊,你子包中的模塊version.py極有可能是被一個glance包同一級別的其他文件導入,比如我們在于glance同級下的一個test.py文件中導入version.py,如下
from glance.api import versions'''
執行結果:
ImportError: No module named 'policy'
''''''
分析:
此時我們導入versions在versions.py中執行
import policy需要找從sys.path也就是從當前目錄找policy.py,
# 這必然是找不到的
'''
絕對導入與相對導入總結
絕對導入與相對導入# 絕對導入: 以執行文件的sys.path為起始點開始導入,稱之為絕對導入
# 優點: 執行文件與被導入的模塊中都可以使用
# 缺點: 所有導入都是以sys.path為起始點,導入麻煩# 相對導入: 參照當前所在文件的文件夾為起始開始查找,稱之為相對導入
# 符號: .代表當前所在文件的文件加,..代表上一級文件夾,...代表上一級的上一級文件夾
# 優點: 導入更加簡單
# 缺點: 只能在導入包中的模塊時才能使用
# 注意:
# 1. 相對導入只能用于包內部模塊之間的相互導入,導入者與被導入者都必須存在于一個包內
# 2. attempted relative import beyond top-level package # 試圖在頂級包之外使用相對導入是錯誤的,言外之# 意,必須在頂級包內使用相對導入,每增加一個.代表跳到上一級文件夾,而上一級不應該超出頂級包