title: Python學(xué)習(xí)記錄day5
tags: python
author: Chinge Yang
date: 2016-11-26
1.多層裝飾器
多層裝飾器的原理是度陆,裝飾器裝飾函數(shù)后哗总,其實(shí)也是一個(gè)函數(shù)夹纫,這樣又可以被裝飾器裝飾栖忠。 編譯是從下至上進(jìn)行的崔挖,執(zhí)行時(shí)是從上至下進(jìn)行贸街。
#!/usr/bin/env python
# _*_coding:utf-8_*_
'''
* Created on 2016/11/29 20:38.
* @author: Chinge_Yang.
'''
USER_INFO = {}
# USER_INFO['is_login'] = True
# USER_INFO['user_type'] = 2
def check_login(func):
def inner(*args, **kwargs):
if USER_INFO.get("is_login", None):
ret = func(*args, **kwargs)
return ret
else:
print("請(qǐng)登錄")
return inner
def check_admin(func):
def inner(*args, **kwargs):
if USER_INFO.get('user_type', None) == 2:
ret = func(*args, **kwargs)
return ret
else:
print('無(wú)權(quán)限查看')
return inner
@check_login
@check_admin
def index():
"""
管理員的功能
:return:
"""
print('Index')
@check_login
def home():
"""
普通用戶功能
:return:
"""
print("home")
def login():
user = input("請(qǐng)輸入用戶名:")
if user == "admin":
USER_INFO["is_login"] = True
USER_INFO["user_type"] = 2
else:
USER_INFO["is_login"] = True
USER_INFO["user_type"] = 1
def main():
while True:
inp = input("1.登錄;2.查看信息狸相;3.超級(jí)管理員管理\n >>>")
if inp == "1":
login()
elif inp == "2":
home()
elif inp == "3":
index()
elif inp == "q":
exit()
main()
2.字符串格式化
Python的字符串格式化有兩種方式: 百分號(hào)方式薛匪、format方式
百分號(hào)的方式相對(duì)來(lái)說(shuō)比較老,而format方式則是比較先進(jìn)的方式脓鹃,企圖替換古老的方式逸尖,目前兩者并存。[PEP-3101]
This PEP proposes a new system for built-in string formatting operations, intended as a replacement for the existing '%' string formatting operator.
1.百分號(hào)方式
%[(name)][flags][width].[precision]typecode
- (name) 可選将谊,用于選擇指定的key
- flags 可選冷溶,可供選擇的值有:
+ 右對(duì)齊;正數(shù)前加正好尊浓,負(fù)數(shù)前加負(fù)號(hào)逞频;
- 左對(duì)齊;正數(shù)前無(wú)符號(hào)栋齿,負(fù)數(shù)前加負(fù)號(hào)苗胀;
空格 右對(duì)齊;正數(shù)前加空格瓦堵,負(fù)數(shù)前加負(fù)號(hào)基协;
0 右對(duì)齊;正數(shù)前無(wú)符號(hào)菇用,負(fù)數(shù)前加負(fù)號(hào)澜驮;用0填充空白處 - width 可選,占有寬度
- .precision 可選惋鸥,小數(shù)點(diǎn)后保留的位數(shù)
- typecode 必選
s杂穷,獲取傳入對(duì)象的str方法的返回值,并將其格式化到指定位置
r卦绣,獲取傳入對(duì)象的repr方法的返回值耐量,并將其格式化到指定位置
c,整數(shù):將數(shù)字轉(zhuǎn)換成其unicode對(duì)應(yīng)的值滤港,10進(jìn)制范圍為 0 <= i <= 1114111(py27則只支持0-255)廊蜒;字符:將字符添加到指定位置
o,將整數(shù)轉(zhuǎn)換成 八 進(jìn)制表示溅漾,并將其格式化到指定位置
x山叮,將整數(shù)轉(zhuǎn)換成十六進(jìn)制表示添履,并將其格式化到指定位置
d缝龄,將整數(shù)汰现、浮點(diǎn)數(shù)轉(zhuǎn)換成 十 進(jìn)制表示叔壤,并將其格式化到指定位置
E,將整數(shù)炼绘、浮點(diǎn)數(shù)轉(zhuǎn)換成科學(xué)計(jì)數(shù)法嗅战,并將其格式化到指定位置(大寫E)
f, 將整數(shù)驮捍、浮點(diǎn)數(shù)轉(zhuǎn)換成浮點(diǎn)數(shù)表示东且,并將其格式化到指定位置(默認(rèn)保留小數(shù)點(diǎn)后6位)
F本讥,同上
g拷沸,自動(dòng)調(diào)整將整數(shù)撞芍、浮點(diǎn)數(shù)轉(zhuǎn)換成浮點(diǎn)型或科學(xué)計(jì)數(shù)法表示(超過(guò)6位數(shù)用科學(xué)計(jì)數(shù)法),并將其格式化到指定位置(如果是科學(xué)計(jì)數(shù)則是e验毡;)
G米罚,自動(dòng)調(diào)整將整數(shù)录择、浮點(diǎn)數(shù)轉(zhuǎn)換成浮點(diǎn)型或科學(xué)計(jì)數(shù)法表示(超過(guò)6位數(shù)用科學(xué)計(jì)數(shù)法)碗降,并將其格式化到指定位置(如果是科學(xué)計(jì)數(shù)則是E讼渊;)
%爪幻,當(dāng)字符串中存在格式化標(biāo)志時(shí)须误,需要用 %%表示一個(gè)百分號(hào)
注:Python中百分號(hào)格式化是不存在自動(dòng)將整數(shù)轉(zhuǎn)換成二進(jìn)制表示的方式
常用格式化:
tpl = "i am %s" % "ygqygq2"
tpl = "i am %s age %d" % ("ygqygq2", 27)
tpl = "i am %(name)s age %(age)d" % {"name": "ygqgyq2", "age": 27}
tpl = "percent %.2f" % 99.97623
tpl = "i am %(pp).2f" % {"pp": 123.425556, }
tpl = "i am %.2f %%" % {"pp": 123.425556, }
2.Format方式
[[fill]align][sign][#][0][width][,][.precision][type]
- fill 【可選】空白處填充的字符
- align 【可選】對(duì)齊方式(需配合width使用)
<京痢,內(nèi)容左對(duì)齊
>祭椰,內(nèi)容右對(duì)齊(默認(rèn))
=方淤,內(nèi)容右對(duì)齊携茂,將符號(hào)放置在填充字符的左側(cè)邑蒋,且只對(duì)數(shù)字類型有效按厘。即使:符號(hào)+填充物+數(shù)字
^逮京,內(nèi)容居中
sign 【可選】有無(wú)符號(hào)數(shù)字
+懒棉,正號(hào)加正策严,負(fù)號(hào)加負(fù)妻导;
-,正號(hào)不變术浪,負(fù)號(hào)加負(fù)胰苏;
空格 硕并,正號(hào)空格倔毙,負(fù)號(hào)加負(fù)普监;
# 【可選】對(duì)于二進(jìn)制琉兜、八進(jìn)制、十六進(jìn)制豌蟋,如果加上#梧疲,會(huì)顯示0b/0o/0x,否則不顯示
缭受, 【可選】為數(shù)字添加分隔符米者,如:1,000,000
width 【可選】格式化位所占寬度
.precision 【可選】小數(shù)位保留精度
type 【可選】格式化類型
傳入” 字符串類型 “的參數(shù)
s蔓搞,格式化字符串類型數(shù)據(jù)
空白喂分,未指定類型蒲祈,則默認(rèn)是None蜒车,同s
傳入“ 整數(shù)類型 ”的參數(shù)
b酿愧,將10進(jìn)制整數(shù)自動(dòng)轉(zhuǎn)換成2進(jìn)制表示然后格式化
c嬉挡,將10進(jìn)制整數(shù)自動(dòng)轉(zhuǎn)換為其對(duì)應(yīng)的unicode字符
d,十進(jìn)制整數(shù)
o因谎,將10進(jìn)制整數(shù)自動(dòng)轉(zhuǎn)換成8進(jìn)制表示然后格式化财岔;
x匠璧,將10進(jìn)制整數(shù)自動(dòng)轉(zhuǎn)換成16進(jìn)制表示然后格式化(小寫x)
X夷恍,將10進(jìn)制整數(shù)自動(dòng)轉(zhuǎn)換成16進(jìn)制表示然后格式化(大寫X)
傳入“ 浮點(diǎn)型或小數(shù)類型 ”的參數(shù)
e酿雪, 轉(zhuǎn)換為科學(xué)計(jì)數(shù)法(小寫e)表示指黎,然后格式化州丹;
E当叭, 轉(zhuǎn)換為科學(xué)計(jì)數(shù)法(大寫E)表示蚁鳖,然后格式化;
f 醉箕, 轉(zhuǎn)換為浮點(diǎn)型(默認(rèn)小數(shù)點(diǎn)后保留6位)表示讥裤,然后格式化己英;
F, 轉(zhuǎn)換為浮點(diǎn)型(默認(rèn)小數(shù)點(diǎn)后保留6位)表示荣瑟,然后格式化笆焰;
g嚷掠, 自動(dòng)在e和f中切換
G叠国, 自動(dòng)在E和F中切換
%戴尸,顯示百分比(默認(rèn)顯示小數(shù)點(diǎn)后6位)
常用格式化:
tpl = "i am {}, age {}, {}".format("seven", 18, 'alex')
tpl = "i am {}, age {}, {}".format(*["seven", 18, 'alex'])
tpl = "i am {0}, age {1}, really {0}".format("seven", 18)
tpl = "i am {0}, age {1}, really {0}".format(*["seven", 18])
tpl = "i am {name}, age {age}, really {name}".format(name="seven", age=18)
tpl = "i am {name}, age {age}, really {name}".format(**{"name": "seven", "age": 18})
tpl = "i am {0[0]}, age {0[1]}, really {0[2]}".format([1, 2, 3], [11, 22, 33])
tpl = "i am {:s}, age {:d}, money {:f}".format("seven", 18, 88888.1)
tpl = "i am {:s}, age {:d}".format(*["seven", 18])
tpl = "i am {name:s}, age {age:d}".format(name="seven", age=18)
tpl = "i am {name:s}, age {age:d}".format(**{"name": "seven", "age": 18})
tpl = "numbers: {:b},{:o},{:d},{:x},{:X}, {:%}".format(15, 15, 15, 15, 15, 15.87623, 2)
tpl = "numbers: {:b},{:o},{:d},{:x},{:X}, {:%}".format(15, 15, 15, 15, 15, 15.87623, 2)
tpl = "numbers: {0:b},{0:o},{0:d},{0:x},{0:X}, {0:%}".format(15)
tpl = "numbers: {num:b},{num:o},{num:d},{num:x},{num:X}, {num:%}".format(num=15)
更多格式化操作:https://docs.python.org/3/library/string.html
3.迭代器和生成器
1.迭代器
迭代器是訪問(wèn)集合元素的一種方式。迭代器對(duì)象從集合的第一個(gè)元素開(kāi)始訪問(wèn)挎峦,直到所有的元素被訪問(wèn)完結(jié)束坦胶。迭代器只能往前不會(huì)后退顿苇,不過(guò)這也沒(méi)什么纪岁,因?yàn)槿藗兒苌僭诘局型笸酸:病A硗庖旁觯鞯囊淮髢?yōu)點(diǎn)是不要求事先準(zhǔn)備好整個(gè)迭代過(guò)程中所有的元素做修。迭代器僅僅在迭代到某個(gè)元素時(shí)才計(jì)算該元素缓待,而在這之前或之后旋炒,元素可以不存在或者被銷毀瘫镇。這個(gè)特點(diǎn)使得它特別適合用于遍歷一些巨大的或是無(wú)限的集合铣除,比如幾個(gè)G的文件
特點(diǎn):
訪問(wèn)者不需要關(guān)心迭代器內(nèi)部的結(jié)構(gòu)尚粘,僅需通過(guò)next()方法不斷去取下一個(gè)內(nèi)容
不能隨機(jī)訪問(wèn)集合中的某個(gè)值 郎嫁,只能從頭到尾依次訪問(wèn)
訪問(wèn)到一半時(shí)不能往回退
便于循環(huán)比較大的數(shù)據(jù)集合泽铛,節(jié)省內(nèi)存
>>> a = iter([1,2,3,4,5])
>>> a
<list_iterator object at 0x101402630>
>>> a.__next__()
1
>>> a.__next__()
2
>>> a.__next__()
3
>>> a.__next__()
4
>>> a.__next__()
5
>>> a.__next__()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
StopIteration
2.生成器
一個(gè)函數(shù)調(diào)用時(shí)返回一個(gè)迭代器杠茬,那這個(gè)函數(shù)就叫做生成器(generator)瓢喉;如果函數(shù)中包含yield語(yǔ)法灯荧,那這個(gè)函數(shù)就會(huì)變成生成器逗载;
def func():
print(11)
yield 1
print(22)
yield 2
print(33)
yield 3
print(44)
yield 4
上述代碼中:func是函數(shù)稱為生成器厉斟,當(dāng)執(zhí)行此函數(shù)func()時(shí)會(huì)得到一個(gè)迭代器擦秽。
>>> temp = func()
>>> temp.__next__()
11
1
>>> temp.__next__()
22
2
>>> temp.__next__()
33
3
>>> temp.__next__()
44
4
>>> temp.__next__()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
StopIteration
4.函數(shù)遞歸
在函數(shù)內(nèi)部感挥,可以調(diào)用其他函數(shù)触幼。如果一個(gè)函數(shù)在內(nèi)部調(diào)用自身本身置谦,這個(gè)函數(shù)就是遞歸函數(shù)媒峡。
def func(n):
n += 1
if n >= 4:
return "end"
return func(n)
res = func(1)
print(res)
遞歸函數(shù)的優(yōu)點(diǎn)是定義簡(jiǎn)單半哟,邏輯清晰寓涨。理論上贱田,所有的遞歸函數(shù)都可以寫成循環(huán)的方式,但循環(huán)的邏輯不如遞歸清晰耗拓。
使用遞歸函數(shù)需要注意防止棧溢出乔询。
詳細(xì)請(qǐng)看廖雪峰的官方網(wǎng)站中遞歸函數(shù)
5.模塊
為了編寫可維護(hù)的代碼竿刁,我們把很多函數(shù)分組食拜,分別放到不同的文件里负甸,這樣呻待,每個(gè)文件包含的代碼就相對(duì)較少蚕捉,很多編程語(yǔ)言都采用這種組織代碼的方式鱼冀。在Python中千绪,一個(gè).py文件就稱之為一個(gè)模塊(Module)盹靴。
模塊分為三種:
* 自定義模塊
* 第三方模塊
* 內(nèi)置模塊
1.使用模塊有什么好處稿静?
1. 最大的好處是大大提高了代碼的可維護(hù)性改备。
2. 使用模塊還可以避免函數(shù)名和變量名沖突悬钳。
2.導(dǎo)入模塊
單模塊:import
嵌套在文件夾下:
from xxx import xxx
from xxx import as ooo
3.第三方模塊
pip3安裝(pip安裝)
pip3 install requests
源碼安裝
curl -OL https://github.com/kennethreitz/requests/tarball/master
解壓后,進(jìn)入目錄
python setup.py install
6.序列化
Python中用于序列化的兩個(gè)模塊
- json 用于【字符串】和【python基本數(shù)據(jù)類型】間進(jìn)行轉(zhuǎn)換
- pickle 用于【python特有的類型】和【python基本數(shù)據(jù)類型】間進(jìn)行轉(zhuǎn)換
Json模塊提供了四個(gè)功能:dumps母剥、dump环疼、loads秦爆、load
pickle模塊提供了四個(gè)功能:dumps等限、dump形娇、loads桐早、load
json相關(guān)用法:
import json
dict = {'k1': 'v1'}
print(dict, type(dict))
# 將python基本數(shù)據(jù)類型轉(zhuǎn)換成字符串形式
res = json.dumps(dict)
print(res, type(res))
{'k1': 'v1'} <class 'dict'>
{"k1": "v1"} <class 'str'>
import json
# 將python字符串形式轉(zhuǎn)換成基本數(shù)據(jù)類型
s1 = '{"k1": 123}'
dict = json.loads(s1) # 反序列化時(shí),一定要使用 ""
print(dict, type(dict))
{'k1': 123} <class 'dict'>
import json
li = [11,22,33]
json.dump(li,open('test.txt','w'))
li = json.load(open('test.txt','r'))
print(type(li),li)
pickle相關(guān)用法:
import pickle
li = [11,22,33]
r = pickle.dumps(li)
print(r)
res = pickle.loads(r)
print(res)
b'\x80\x03]q\x00(K\x0bK\x16K!e.'
[11, 22, 33]
li = [11,22,33]
pickle.dump(li, open('test4.txt', 'wb'))
res = pickle.load(open('test4.txt', 'rb'))
print(res)
[11, 22, 33]
json和pickle對(duì)比:
1. json更適合跨語(yǔ)言陶衅,字符串搀军,基本數(shù)據(jù)類型
2. pickle更適合python所有類型的序列化操作
7.time & datetime模塊
#_*_coding:utf-8_*_
__author__ = 'Alex Li'
import time
# print(time.clock()) #返回處理器時(shí)間,3.3開(kāi)始已廢棄 , 改成了time.process_time()測(cè)量處理器運(yùn)算時(shí)間,不包括sleep時(shí)間,不穩(wěn)定,mac上測(cè)不出來(lái)
# print(time.altzone) #返回與utc時(shí)間的時(shí)間差,以秒計(jì)算\
# print(time.asctime()) #返回時(shí)間格式"Fri Aug 19 11:14:16 2016",
# print(time.localtime()) #返回本地時(shí)間 的struct time對(duì)象格式
# print(time.gmtime(time.time()-800000)) #返回utc時(shí)間的struc時(shí)間對(duì)象格式
# print(time.asctime(time.localtime())) #返回時(shí)間格式"Fri Aug 19 11:14:16 2016",
#print(time.ctime()) #返回Fri Aug 19 12:38:29 2016 格式, 同上
# 日期字符串 轉(zhuǎn)成 時(shí)間戳
# string_2_struct = time.strptime("2016/05/22","%Y/%m/%d") #將 日期字符串 轉(zhuǎn)成 struct時(shí)間對(duì)象格式
# print(string_2_struct)
# #
# struct_2_stamp = time.mktime(string_2_struct) #將struct時(shí)間對(duì)象轉(zhuǎn)成時(shí)間戳
# print(struct_2_stamp)
#將時(shí)間戳轉(zhuǎn)為字符串格式
# print(time.gmtime(time.time()-86640)) #將utc時(shí)間戳轉(zhuǎn)換成struct_time格式
# print(time.strftime("%Y-%m-%d %H:%M:%S",time.gmtime()) ) #將utc struct_time格式轉(zhuǎn)成指定的字符串格式
#時(shí)間加減
import datetime
# print(datetime.datetime.now()) #返回 2016-08-19 12:47:03.941925
#print(datetime.date.fromtimestamp(time.time()) ) # 時(shí)間戳直接轉(zhuǎn)成日期格式 2016-08-19
# print(datetime.datetime.now() )
# print(datetime.datetime.now() + datetime.timedelta(3)) #當(dāng)前時(shí)間+3天
# print(datetime.datetime.now() + datetime.timedelta(-3)) #當(dāng)前時(shí)間-3天
# print(datetime.datetime.now() + datetime.timedelta(hours=3)) #當(dāng)前時(shí)間+3小時(shí)
# print(datetime.datetime.now() + datetime.timedelta(minutes=30)) #當(dāng)前時(shí)間+30分
#
# c_time = datetime.datetime.now()
# print(c_time.replace(minute=3,hour=2)) #時(shí)間替換
8.logging模塊
很多程序都有記錄日志的需求敛摘,并且日志中包含的信息即有正常的程序訪問(wèn)日志兄淫,還可能有錯(cuò)誤拖叙、警告等信息輸出,python的logging模塊提供了標(biāo)準(zhǔn)的日志接口挖滤,你可以通過(guò)它存儲(chǔ)各種格式的日志,logging的日志可以分為 debug(), info(), warning(), error() and critical() 5個(gè)級(jí)別浅役,下面我們看一下怎么用斩松。
最簡(jiǎn)單用法
import logging
logging.warning("user [alex] attempted wrong password more than 3 times")
logging.critical("server is down")
WARNING:root:user [alex] attempted wrong password more than 3 times
CRITICAL:root:server is down
Level | When it’s used |
---|---|
DEBUG | Detailed information, typically of interest only when diagnosing problems. |
INFO | Confirmation that things are working as expected. |
WARNING | An indication that something unexpected happened, or indicative of some problem in the near future (e.g. ‘disk space low’). The software is still working as expected. |
ERROR | Due to a more serious problem, the software has not been able to perform some function. |
CRITICAL | A serious error, indicating that the program itself may be unable to continue running. |
看一下這幾個(gè)日志級(jí)別分別代表什么意思
Level | When it’s used |
---|---|
DEBUG | Detailed information, typically of interest only when diagnosing problems. |
INFO | Confirmation that things are working as expected. |
WARNING | An indication that something unexpected happened, or indicative of some problem in the near future (e.g. ‘disk space low’). The software is still working as expected. |
ERROR | Due to a more serious problem, the software has not been able to perform some function. |
CRITICAL | A serious error, indicating that the program itself may be unable to continue running. |
如果想把日志寫到文件里,也很簡(jiǎn)單
import logging
logging.basicConfig(filename='example.log',level=logging.?INFO)
logging.debug('This message should go to the log file')
logging.info('So should this')
logging.warning('And this, too')
其中下面這句中的level=loggin.INFO意思是觉既,把日志紀(jì)錄級(jí)別設(shè)置為INFO惧盹,也就是說(shuō)乳幸,只有比日志是INFO或比INFO級(jí)別更高的日志才會(huì)被紀(jì)錄到文件里钧椰,在這個(gè)例子粹断, 第一條日志是不會(huì)被紀(jì)錄的,如果希望紀(jì)錄debug的日志嫡霞,那把日志級(jí)別改成DEBUG就行了瓶埋。
logging.basicConfig(filename='example.log',level=logging.INFO)
感覺(jué)上面的日志格式忘記加上時(shí)間啦,日志不知道時(shí)間怎么行呢诊沪,下面就來(lái)加上!
import logging
logging.basicConfig(format='%(asctime)s %(message)s', datefmt='%m/%d/%Y %I:%M:%S %p')
logging.warning('is when this event was logged.')
12/12/2010 11:46:36 AM is when this event was logged.
%(name)s | Logger的名字 |
---|---|
%(levelno)s | 數(shù)字形式的日志級(jí)別 |
%(levelname)s | 文本形式的日志級(jí)別 |
%(pathname)s | 調(diào)用日志輸出函數(shù)的模塊的完整路徑名养筒,可能沒(méi)有 |
%(filename)s | 調(diào)用日志輸出函數(shù)的模塊的文件名 |
%(module)s | 調(diào)用日志輸出函數(shù)的模塊名 |
%(funcName)s | 調(diào)用日志輸出函數(shù)的函數(shù)名 |
%(lineno)d | 調(diào)用日志輸出函數(shù)的語(yǔ)句所在的代碼行 |
%(created)f | 當(dāng)前時(shí)間,用UNIX標(biāo)準(zhǔn)的表示時(shí)間的浮 點(diǎn)數(shù)表示 |
%(relativeCreated)d | 輸出日志信息時(shí)的端姚,自Logger創(chuàng)建以 來(lái)的毫秒數(shù) |
%(asctime)s | 字符串形式的當(dāng)前時(shí)間晕粪。默認(rèn)格式是 “2003-07-08 16:49:45,896”。逗號(hào)后面的是毫秒 |
%(thread)d | 線程ID寄锐”啵可能沒(méi)有 |
%(threadName)s | 線程名¢掀停可能沒(méi)有 |
%(process)d | 進(jìn)程ID剩膘。可能沒(méi)有 |
%(message)s | 用戶輸出的消息 |
日志格式
%(name)s | Logger的名字 |
---|---|
%(levelno)s | 數(shù)字形式的日志級(jí)別 |
%(levelname)s | 文本形式的日志級(jí)別 |
%(pathname)s | 調(diào)用日志輸出函數(shù)的模塊的完整路徑名盆顾,可能沒(méi)有 |
%(filename)s | 調(diào)用日志輸出函數(shù)的模塊的文件名 |
%(module)s | 調(diào)用日志輸出函數(shù)的模塊名 |
%(funcName)s | 調(diào)用日志輸出函數(shù)的函數(shù)名 |
%(lineno)d | 調(diào)用日志輸出函數(shù)的語(yǔ)句所在的代碼行 |
%(created)f | 當(dāng)前時(shí)間怠褐,用UNIX標(biāo)準(zhǔn)的表示時(shí)間的浮 點(diǎn)數(shù)表示 |
%(relativeCreated)d | 輸出日志信息時(shí)的,自Logger創(chuàng)建以 來(lái)的毫秒數(shù) |
%(asctime)s | 字符串形式的當(dāng)前時(shí)間您宪。默認(rèn)格式是 “2003-07-08 16:49:45,896”奈懒。逗號(hào)后面的是毫秒 |
%(thread)d | 線程ID∠芫蓿可能沒(méi)有 |
%(threadName)s | 線程名磷杏。可能沒(méi)有 |
%(process)d | 進(jìn)程ID捏卓〖觯可能沒(méi)有 |
%(message)s | 用戶輸出的消息 |
如果想同時(shí)把log打印在屏幕和文件日志里,就需要了解一點(diǎn)復(fù)雜的知識(shí) 了
Python 使用logging模塊記錄日志涉及四個(gè)主要類怠晴,使用官方文檔中的概括最為合適:
1. logger提供了應(yīng)用程序可以直接使用的接口遥金;
2. handler將(logger創(chuàng)建的)日志記錄發(fā)送到合適的目的輸出;
3. filter提供了細(xì)度設(shè)備來(lái)決定輸出哪條日志記錄蒜田;
4. formatter決定日志記錄的最終輸出格式稿械。
logger
每個(gè)程序在輸出信息之前都要獲得一個(gè)Logger。Logger通常對(duì)應(yīng)了程序的模塊名冲粤,比如聊天工具的圖形界面模塊可以這樣獲得它的Logger:
LOG=logging.getLogger(”chat.gui”)
而核心模塊可以這樣:
LOG=logging.getLogger(”chat.kernel”)
Logger.setLevel(lel):指定最低的日志級(jí)別美莫,低于lel的級(jí)別將被忽略页眯。debug是最低的內(nèi)置級(jí)別,critical為最高
Logger.addFilter(filt)厢呵、Logger.removeFilter(filt):添加或刪除指定的filter
Logger.addHandler(hdlr)餐茵、Logger.removeHandler(hdlr):增加或刪除指定的handler
Logger.debug()、Logger.info()述吸、Logger.warning()忿族、Logger.error()、Logger.critical():可以設(shè)置的日志級(jí)別
handler
handler對(duì)象負(fù)責(zé)發(fā)送相關(guān)的信息到指定目的地蝌矛。Python的日志系統(tǒng)有多種Handler可以使用道批。有些Handler可以把信息輸出到控制臺(tái),有些Logger可以把信息輸出到文件入撒,還有些 Handler可以把信息發(fā)送到網(wǎng)絡(luò)上隆豹。如果覺(jué)得不夠用,還可以編寫自己的Handler茅逮×模可以通過(guò)addHandler()方法添加多個(gè)多handler
Handler.setLevel(lel):指定被處理的信息級(jí)別,低于lel級(jí)別的信息將被忽略
Handler.setFormatter():給這個(gè)handler選擇一個(gè)格式
Handler.addFilter(filt)献雅、Handler.removeFilter(filt):新增或刪除一個(gè)filter對(duì)象
每個(gè)Logger可以附加多個(gè)Handler碉考。接下來(lái)我們就來(lái)介紹一些常用的Handler:
- logging.StreamHandler
使用這個(gè)Handler可以向類似與sys.stdout或者sys.stderr的任何文件對(duì)象(file object)輸出信息。它的構(gòu)造函數(shù)是:
StreamHandler([strm])
其中strm參數(shù)是一個(gè)文件對(duì)象挺身。默認(rèn)是sys.stderr - logging.FileHandler
和StreamHandler類似侯谁,用于向一個(gè)文件輸出日志信息。不過(guò)FileHandler會(huì)幫你打開(kāi)這個(gè)文件章钾。它的構(gòu)造函數(shù)是:
FileHandler(filename[,mode])
filename是文件名墙贱,必須指定一個(gè)文件名。
mode是文件的打開(kāi)方式贱傀。參見(jiàn)Python內(nèi)置函數(shù)open()的用法惨撇。默認(rèn)是’a',即添加到文件末尾府寒。 - logging.handlers.RotatingFileHandler
這個(gè)Handler類似于上面的FileHandler魁衙,但是它可以管理文件大小。當(dāng)文件達(dá)到一定大小之后椰棘,它會(huì)自動(dòng)將當(dāng)前日志文件改名纺棺,然后創(chuàng)建 一個(gè)新的同名日志文件繼續(xù)輸出榄笙。比如日志文件是chat.log邪狞。當(dāng)chat.log達(dá)到指定的大小之后,RotatingFileHandler自動(dòng)把 文件改名為chat.log.1茅撞。不過(guò)帆卓,如果chat.log.1已經(jīng)存在巨朦,會(huì)先把chat.log.1重命名為chat.log.2。剑令。糊啡。最后重新創(chuàng)建 chat.log,繼續(xù)輸出日志信息吁津。它的構(gòu)造函數(shù)是:
RotatingFileHandler( filename[, mode[, maxBytes[, backupCount]]])
其中filename和mode兩個(gè)參數(shù)和FileHandler一樣棚蓄。
maxBytes用于指定日志文件的最大文件大小。如果maxBytes為0碍脏,意味著日志文件可以無(wú)限大梭依,這時(shí)上面描述的重命名過(guò)程就不會(huì)發(fā)生。
backupCount用于指定保留的備份文件的個(gè)數(shù)典尾。比如役拴,如果指定為2,當(dāng)上面描述的重命名過(guò)程發(fā)生時(shí)钾埂,原有的chat.log.2并不會(huì)被更名河闰,而是被刪除。 - logging.handlers.TimedRotatingFileHandler
這個(gè)Handler和RotatingFileHandler類似褥紫,不過(guò)姜性,它沒(méi)有通過(guò)判斷文件大小來(lái)決定何時(shí)重新創(chuàng)建日志文件,而是間隔一定時(shí)間就 自動(dòng)創(chuàng)建新的日志文件髓考。重命名的過(guò)程與RotatingFileHandler類似污抬,不過(guò)新的文件不是附加數(shù)字,而是當(dāng)前時(shí)間绳军。它的構(gòu)造函數(shù)是:
TimedRotatingFileHandler( filename [,when [,interval [,backupCount]]])
其中filename參數(shù)和backupCount參數(shù)和RotatingFileHandler具有相同的意義印机。
interval是時(shí)間間隔。
when參數(shù)是一個(gè)字符串门驾。表示時(shí)間間隔的單位射赛,不區(qū)分大小寫。它有以下取值:
S 秒
M 分
H 小時(shí)
D 天
W 每星期(interval==0時(shí)代表星期一)
midnight 每天凌晨
import logging
#create logger
logger = logging.getLogger('TEST-LOG')
logger.setLevel(logging.DEBUG)
# create console handler and set level to debug
ch = logging.StreamHandler()
ch.setLevel(logging.DEBUG)
# create file handler and set level to warning
fh = logging.FileHandler("access.log")
fh.setLevel(logging.WARNING)
# create formatter
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
# add formatter to ch and fh
ch.setFormatter(formatter)
fh.setFormatter(formatter)
# add ch and fh to logger
logger.addHandler(ch)
logger.addHandler(fh)
# 'application' code
logger.debug('debug message')
logger.info('info message')
logger.warn('warn message')
logger.error('error message')
logger.critical('critical message')
import logging
from logging import handlers
logger = logging.getLogger(__name__)
log_file = "timelog.log"
#fh = handlers.RotatingFileHandler(filename=log_file,maxBytes=10,backupCount=3)
fh = handlers.TimedRotatingFileHandler(filename=log_file,when="S",interval=5,backupCount=3)
formatter = logging.Formatter('%(asctime)s %(module)s:%(lineno)d %(message)s')
fh.setFormatter(formatter)
logger.addHandler(fh)
logger.warning("test1")
logger.warning("test12")
logger.warning("test13")
logger.warning("test14")