包
什麼是包: ---檔案夾下具有__init__.py檔案就是一個包
推薦使用 from . import
包的導入;
- from ss.bake.api.policy import func ---絕對導入
- from ..api.www import ww ww()---相對路徑導入 必須在外部使用
注意點:
- 使用相對路徑必須在最外層報的同級進行導入
- 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)單對檔案流設定某個級别。