python的學習之路day5

大綱:

一、雙層裝飾器html

單層裝飾器python

雙層裝飾器json

原理windows

二、字符串的格式化api

三、format字符串格式化網絡

四、生成器app

五、遞歸ide

六、模塊的安裝函數

七、json模塊工具

八、pickle模塊

九、time模塊

十、datetime模塊

十一、logging模塊

 

雙層裝飾器

仍是老樣,沒有改變:

USER_INFO = {}


def check_login(func):
    def inner(*args, **kwargs):
        if USER_INFO.get("is_login", None):
            # 用get方法拿字典裏面的內容,若是字典裏面沒有咱們要拿的參數,不會報錯,給他默認返回的爲None
            ret = func(*args, **kwargs)
            return ret
        else:
            print("請登陸")

    return inner


def check_admin(func):  # 判斷是否爲管理員用戶
    def inner(*args, **kwargs):
        if USER_INFO.get("is_login", None):
            if USER_INFO.get("user_type", None) == 2:  # 若是用戶類型等於2,表示爲管理員用戶
                ret = func(*args, **kwargs)
                return ret
            else:
                print("無權限查看")  # 否者無權限查看
        else:
            print("請登陸")

    return inner


@check_admin
def index():  # 超級管理員能夠查看
    print("index")


@check_login
def home():  # 登陸能夠查看
    """
    普通用戶的功能
    :return:
    """
    print("home")


def login():  # 登陸
    user = input("請輸入用戶名:")
    if user == "admin":
        USER_INFO["is_login"] = True
        USER_INFO["user_type"] = 2
    else:  # 否者若是不爲admin,表示登陸的用戶爲普通用戶
        USER_INFO["is_login"] = True
        USER_INFO["is_login"] = 1


def main():
    while True:
        inp = input("一、登陸;二、查看信息;3超級管理員\n>>>")
        if inp == "1":
            login()
        elif inp == "2":
            home()
        elif inp == "3":
            index()


main()
v1

輸出:

一、登陸;2、查看信息;3超級管理員
>>>2
請登陸
一、登陸;2、查看信息;3超級管理員
>>>3
請登陸
一、登陸;2、查看信息;3超級管理員
>>>1
請輸入用戶名:user
一、登陸;2、查看信息;3超級管理員
>>>2
home
一、登陸;2、查看信息;3超級管理員
>>>3
無權限查看
一、登陸;2、查看信息;3超級管理員
>>>1
請輸入用戶名:admin
一、登陸;2、查看信息;3超級管理員
>>>2
home
一、登陸;2、查看信息;3超級管理員
>>>3
index
一、登陸;2、查看信息;3超級管理員
>>>
v1的輸出

 

新變化:

# 從版本以一中咱們能夠看到不少咱們的check_admin裏面重複了check_login的代碼(check_admin又判斷登陸,又判斷權限),
# 若是咱們又加上了超級管理員,那咱們就會又寫一個重複的裝飾器,
# 因此咱們須要用到雙層裝飾器,先用check_login,判斷是否登陸,而後用check_admin判斷是否爲管理員
USER_INFO = {}


def check_login(func):
    def inner(*args, **kwargs):
        if USER_INFO.get("is_login", None):
            # 用get方法拿字典裏面的內容,若是字典裏面沒有咱們要拿的參數,不會報錯,給他默認返回的爲None
            ret = func(*args, **kwargs)
            return ret
        else:
            print("請登陸")

    return inner


def check_admin(func):  # 判斷是否爲管理員用戶
    def inner(*args, **kwargs):
        if USER_INFO.get("user_type", None) == 2:  # 若是用戶類型等於2,表示爲管理員用戶
            ret = func(*args, **kwargs)
            return ret
        else:
            print("無權限查看")  # 否者無權限查看

    return inner


# 爲何check_login寫上面,咱們從下向上看,從index()開始,
# 能夠看到先用admin裝飾後,好比變成了nindex這個函數,而後再用login裝飾進行裝飾,好比又變成了nnindex,而後python是從上向下執行,
# 因此python會執行nnindex,判斷是否登陸,而後在執行nindex,判斷是否爲管理員,若是沒有登陸,
# 提示登陸,若是已經登陸(不爲管理員),提示無權限
@check_login
@check_admin
def index():  # 管理員能夠查看
    """
    管理員的功能
    :return:
    """
    print("index")


@check_login
def home():  # 登陸能夠查看
    """
    普通用戶的功能
    :return:
    """
    print("home")


def login():  # 登陸
    user = input("請輸入用戶名:")
    if user == "admin":
        USER_INFO["is_login"] = True
        USER_INFO["user_type"] = 2
    else:  # 否者若是不爲admin,表示登陸的用戶爲普通用戶
        USER_INFO["is_login"] = True
        USER_INFO["is_login"] = 1


def main():
    while True:
        inp = input("一、登陸;二、查看信息;3超級管理員\n>>>")
        if inp == "1":
            login()
        elif inp == "2":
            home()
        elif inp == "3":
            index()


main()
v2

輸出:

一、登陸;2、查看信息;3超級管理員
>>>2
請登陸
一、登陸;2、查看信息;3超級管理員
>>>3
請登陸
一、登陸;2、查看信息;3超級管理員
>>>1
請輸入用戶名:user
一、登陸;2、查看信息;3超級管理員
>>>2
home
一、登陸;2、查看信息;3超級管理員
>>>3
無權限查看
一、登陸;2、查看信息;3超級管理員
>>>1
請輸入用戶名:admin
一、登陸;2、查看信息;3超級管理員
>>>2
home
一、登陸;2、查看信息;3超級管理員
>>>3
index
一、登陸;2、查看信息;3超級管理員
>>>
v2的輸出

輸出效果徹底同樣,注意看v2的註釋

 

裝飾器的原理(多層原理也同樣):

字符串的格式化:

%[(name)] [flags] [width].[precision] typecode
# 字符串格式化
# %[(name)] [flags] [width].[precision] typecode

# 常規的格式化
string = "博客網址:www.cnblogs.com/%s,園齡:%d個月" % ("smelond", 1)
print(string)

# %[(name)]可選,用於指定的key:
string = "博客網址:www.cnblogs.com/%(name)s,園齡:%(age)d個月" % {"name": "smelond", "age": 1}  # 用字典方式
print(string)

# flags 可選,可供選擇的值有(據說沒卵用)
# +   右對齊:正數前加正號,負數前加負號
# -   左對齊:正數前無符號,負數前加負號
# 空格 右對齊:正數前加空格,負數前加負號
# 0   右對齊:正數前無符號,負數前加負號;用0填充空白處
string = "博客網址:www.cnblogs.com/%(name)+20s,園齡:%(age)-10d個月" % {"name": "smelond", "age": 1}  # 佔有20個空格,smelond在其中,向右對齊
print(string)

# width 可選,佔有寬度

# .precision 可選,小數點後保留的位數
string = "數值:%(p).2f" % {"p": 1.23656}  # 在後面加上.而後數字,表明保留幾位,有四捨五入功能
print(string)

# typecode 必選
#         s,獲取傳入對象的__str__方法的返回值,並將其格式化到指定位置
#         r,獲取傳入對象的__repr__方法的返回值,並將其格式化到指定位置(面向對象內容)
#         c,整數:將數字轉換成其unicode對應的值,10進制範圍爲 0 <= i <= 1114111(py27則只支持0-255);字符:將字符添加到指定位置
#         o,將整數轉換成 八  進製表示,並將其格式化到指定位置
#         x,將整數轉換成十六進制表示,並將其格式化到指定位置
string = "%c___%o___%x" % (65, 15, 15)  # 將十進制轉換爲其餘進制(A,17,f)
print(string)

#         d,將整數、浮點數轉換成 十 進製表示,並將其格式化到指定位置
#         e,將整數、浮點數轉換成科學計數法,並將其格式化到指定位置(小寫e)
#         E,將整數、浮點數轉換成科學計數法,並將其格式化到指定位置(大寫E)
#         f, 將整數、浮點數轉換成浮點數表示,並將其格式化到指定位置(默認保留小數點後6位)
#         F,同上
string = "%d--------%f--------%e--------%E-------%.2ef" % (100000000, 1.23456, 10000000, 10000000, 10000000)
print(string)

#         g,自動調整將整數、浮點數轉換成 浮點型或科學計數法表示(超過6位數用科學計數法),並將其格式化到指定位置(若是是科學計數則是e;)
#         G,自動調整將整數、浮點數轉換成 浮點型或科學計數法表示(超過6位數用科學計數法),並將其格式化到指定位置(若是是科學計數則是E;)
string = "%g-------%g-------%G-------%G" % (10000000, 100, 10000000, 100)
print(string)

#         %,當字符串中存在格式化標誌時,須要用 %%表示一個百分號
string = "name:%s %% %%%%" % "smelond"  # 若是須要輸出一個%,可是前面已經有了一個佔位符,那就須要輸出%%才能表明一個%,否者會報錯,須要輸出%%,就須要%%%%
print(string)
#
# 注:Python中百分號格式化是不存在自動將整數轉換成二進制表示的方式
string_formating.py
博客網址:www.cnblogs.com/smelond,園齡:1個月
博客網址:www.cnblogs.com/smelond,園齡:1個月
博客網址:www.cnblogs.com/             smelond,園齡:1         個月
數值:1.24
A___17___f
100000000--------1.234560--------1.000000e+07--------1.000000E+07-------1.00e+07f
1e+07-------100-------1E+07-------100
name:smelond % %%
輸出

 

format格式化:

# [[fill]align] [sign] [#] [0] [widht] [,] [.precision] [type]
# fill         【可選】空白處填充的字符
# align        【可選】對齊方式(需配合width使用)
#   < ,內容左對齊
#   > ,內容右對齊(默認)
#   =,內容右對齊,將符號放置在填充字符的左側,且只對數字類型有效。 即便:符號 + 填充物 + 數字
#   ^ ,內容居中


# sign         【可選】有無符號數字
#   +,正號加正,負號加負;
#   -,正號不變,負號加負;
#   空格 ,正號空格,負號加負;


# #             【可選】對於二進制、八進制、十六進制,若是加上#,會顯示 0b/0o/0x,不然不顯示
# ,            【可選】爲數字添加分隔符,如:1, 000, 000
# width         【可選】格式化位所佔寬度
# .precision    【可選】小數位保留精度
# type          【可選】格式化類型
#   傳入」 字符串類型 「的參數
#       s,格式化字符串類型數據
#       空白,未指定類型,則默認是None,同s
#   傳入「 整數類型 」的參數
#       b,將10進制整數自動轉換成2進製表示而後格式化
#       c,將10進制整數自動轉換爲其對應的unicode字符
#       d,十進制整數
#       o,將10進制整數自動轉換成8進製表示而後格式化;
#       x,將10進制整數自動轉換成16進製表示而後格式化(小寫x)
#       X,將10進制整數自動轉換成16進製表示而後格式化(大寫X)
#   傳入「 浮點型或小數類型 」的參數
#       e, 轉換爲科學計數法(小寫e)表示,而後格式化;
#       E, 轉換爲科學計數法(大寫E)表示,而後格式化;
#       f , 轉換爲浮點型(默認小數點後保留6位)表示,而後格式化;
#       F, 轉換爲浮點型(默認小數點後保留6位)表示,而後格式化;
#       g, 自動在e和f中切換
#       G, 自動在E和F中切換
#       % ,顯示百分比(默認顯示小數點後6位)
 
# 兩個最基本的格式化
string = "asdfasgsdf__{0}__asdf__{0}__adhkg__{1}__".format(123, "smelond")
print(string)  # asdfasgsdf__123__asdf__123__adhkg__smelond__
string = "___{name:s}___{age:d}___{name:s}".format(name="smelond", age=16)
print(string)  # ___smelond___16___smelond

# 一些經常使用的用法
#   空白處填充*,^字符居中,20個空格,s:字符串形式{:*^20s}
#   +有符號數值,d:十進制{:+d}
#   x 直接轉換爲16進制
#   #若是後面輸入的爲x,那就轉換爲16進制後再前面加上0x{:#x}
string = "_____{:*^20s}_____{:+d}_____{:x}_____{:#x}".format("smelond", 123, 15, 15)
print(string)  # _____******smelond*******_____+123_____f_____0xf

string = "百分比:{:%}".format(1.2345)
print(string)  # 百分比:123.450000%
用法
# 一些經常使用的用法
tpl = "i am {},age {},{}".format("seven", 16, "smelond")
print(tpl)  # i am seven,age 16,smelond

tpl = "i am {},age {},{}".format(*["seven", 16, "smelond"])
print(tpl)  # i am seven,age 16,smelond,注意,若是是列表要在前面加上*

tpl = "i am {0},age {1}, really {0}".format("seven", 16)
print(tpl)  # i am seven,age 16, really seven

tpl = "i am {0},age {1}, really {0}".format(*["seven", 16])
print(tpl)  # i am seven,age 16, really seven,列表須要加上*

tpl = "i am {name}, age {age}, really {name}".format(name="smelond", age=16)
print(tpl)  # i am smelond, age 16, really smelond

tpl = "i am {name}, age {age}, really {name}".format(**{"name": "smelond", "age": 16})
print(tpl)  # i am smelond, age 16, really smelond,注意,若是是字典須要加上兩個*

tpl = "i am {0[0]}, age {0[1]}, really {1[2]}".format([1, 2, 3], [11, 22, 33])
print(tpl)  # i am 1, age 2, really 33,列表裏面的列表

tpl = "i am {:s}, age {:d}".format("smelond", 16)
print(tpl)  # i am smelond, age 16

tpl = "i am {name:s}, age {age:d}".format(name="smelond", age=16)
print(tpl)  # i am smelond, age 16

tpl = "i am {name:s}, age {age:d}".format(**{"name": "smelond", "age": 16})
print(tpl)  # i am smelond, age 16,字典須要加上**

tpl = "numbers:{:b},{:o},{:d},{:x},{:X},{:%}".format(15, 15, 15, 15, 15, 15.87612)
print(tpl)  # s:1111,17,15,f,F,1500.000000%

tpl = "numbers:{0:b},{0:o},{0:d},{0:x},{0:X},{0:%}".format(15)
print(tpl)  # s:1111,17,15,f,F,1500.000000%

tpl = "numbers:{num:b},{num:o},{num:d},{num:x},{num:X},{num:%}".format(num=15)
print(tpl)  # s:1111,17,15,f,F,1500.000000%
一些經常使用的用法

 

生成器的使用(生成器是使用函數建立的):

# 普通函數
# def func():
#     return 123
#
#
# ret = func()  # 執行函數拿結果

# 生成器
def func():
    # print("start")
    print(111)
    yield 1
    print(222)
    yield 2
    print(333)
    yield 3  # 若是在函數裏面出現了yield,這個函數就稱之爲生成器


ret = func()
print(ret)
# for i in ret:
#     print(i)  # 輸出
# 循環第一次的時候就進入func函數裏面去,進入後拿走yield後面的值,因此輸出1,而後循環第二次,
# 第二次進入func函數時,找到上一次結尾的位置,從結尾的位置又開始循環(往下走),因此就是輸出2
# 而後第三次
r1 = ret.__next__()  # 進入函數找到yield,獲取yield後面的數據,而後咱們就拿到了1
print(r1)
r2 = ret.__next__()  # 進入函數找到yield,獲取yield後面的數據,而後咱們就拿到了2
print(r2)
r3 = ret.__next__()  # 進入函數找到yield,獲取yield後面的數據,而後咱們就拿到了3
print(r3)


# r4 = ret.__next__()
# print(r4)  # 從函數裏面能夠看到沒有第4個yield,因此這句要報錯


#輸出:
111
1
222
2
333
3
生成器的使用
# 基於生成器實現range功能
def myrange(arg):  # 至關於這是一個生成器
    start = 0
    while True:
        if start > arg:
            return
        yield start
        start += 1


ret = myrange(3)
# for i in ret:
#     print(i)
r = ret.__next__()
print(r)
r = ret.__next__()
print(r)
r = ret.__next__()
print(r)
r = ret.__next__()
print(r)
# r = ret.__next__()
# print(r)#第四次確定報錯,由於只循環3次,從0開始

輸出:
0
1
2
3
基於生成器實現range功能

 

python的遞歸:

本身拿着windows自帶的畫圖工具畫的,將就看吧,是有點醜

 

代碼貼上

# 一個遞給另一個,一個簡單的原理
def d():
    r = "end"  # 將字符串end賦給r
    return r  # 返回一個變量r


def c():
    r = d()  # 拿到函數d的返回值
    return r


def b():
    r = c()  # 拿到函數c的返回值
    return r


def a():
    r = b()  # 拿到函數b的返回值
    print(r)  # 拿到結果後輸出


a()  # 輸出end


# 遞歸
# 執行第一次時的效果
def func(n):  # 如今n=1
    n += 1  # n等於2
    if n >= 4:  # 當若是n>=4的時候
        return "end"  # 遇到return直接退出,而後返回一個字符串end
    return func(n)  # 上面if若是沒執行,確定會執行這句,返回func函數,如今的n=2


r = func(1)  # 傳入實參1到func函數裏去慢慢執行,而後接收返回值
print(r)  #輸出end
遞歸

用遞歸實現一個1*2*3*4*5*6*7:

def func(n, x):  # n=1,x=1.......n=2,x=2.......n=3,x=6
    n += 1  # n=2.......n=3.......n=4
    x *= n  # x=x*n,x=2.......x=x*n,x=6.......x=x*n,x=24
    if n >= 7:  # 直到n等於7的時候,將x返回
        return x
    return func(n, x)  # n=2,x=2.......n=3,x=6.......

r = func(1, 1)
print(r)

輸出:5040
個人思路
def func(num):
    if num == 1:
        return 1
    return num * func(num - 1)

x = func(7)
print(x)

輸出:5040
老師的思路

事實證實,我太笨了,我那個太複雜了,並且全是運算,可是老師的感受就輕快明瞭

 

模塊的使用及安裝

# 導入模塊
# 單模塊
import call_m  # 直接調用當前目錄下的call_m.py文件
import lib.commons  # 調用lib目錄下的commons.py文件
# 嵌套在文件夾下的模塊
from lib import commons
from src import commons as xxx  # 若是重名,咱們能夠用as給他作一個別名


# call_m.login()  # 輸出裏面的方法,就至關於調用了裏面的函數
# lib.commons.logout()
模塊

 安裝requests模塊

  pip3 install requests

 

json模塊

json只能處理基本的數據類型

import json

# json只能處理基本的數據類型
dic = {"k1": "v1"}
print(dic, type(dic))
# 用json模塊將python的基本數據類型轉換成爲字符串形式
result = json.dumps(dic)
print(result, type(result))

s1 = '{"k1":123}'
# json將python字符串形式轉換成爲基本數據類型
dic = json.loads(s1)
print(dic, type(dic))

# py基本數據類型轉換字符串
r = json.dumps([11, 22, 33])
# li = "['smelond','amanda']"  #這種方法不行,由於其餘語言裏面 ' 和 "跟python不同
li = '["smelond","amanda"]'  # 反序列化時,必定要使用  "
print(r, type(r))
ret = json.loads(li)
print(ret, type(ret))

li = [11, 22, 33]
json.dump(li, open("db", "w"))  # dump先把他進行序列化,而後寫到文件裏面
li = json.load(open("db", "r"))  # 從文件裏面把字符串讀出來,讀出來後會轉換成爲列表類型
print(li, type(li))

 

用json加requests模塊調用天氣的api接口

import json
import requests
import sys
response = requests.get("http://www.sojson.com/open/api/weather/json.shtml?city=雙流")
response.encoding = "utf-8"
dic = json.loads(response.text)
print(dic)

 

json/pickle
json更加適合跨語言操做,由於它傳遞的是字符串,基本數據類型
pickle,對python的全部類型的序列化,僅適用與python

 

pickle模塊

pickle支持任何的類型

# pickle支持任何的類型
import pickle

# dumps a loads
li = [11, 22, 33]
r = pickle.dumps(li)  # 字符方式
print(r)

result = pickle.loads(r)
print(result)

# dump a load
li = [11, 22, 33]
pickle.dump(li, open("db", "wb"))  ##pickle是以字符方式存取,因此要加上b

resul = pickle.load(open("db", "rb"))  # 讀取
print(resul)

 

time&datetime模塊

time模塊

import time

print(time.process_time())  # 測量處理器運算時間,不包括sleep時間,不穩定
print(time.altzone)  # 返回與utc時間的時間差,以秒計算
print(time.asctime())  # 返回時間格式「Sat Dec 30 17:32:59 2017」
print(time.localtime())  # 返回本地時間的struct time對象格式
tm = time.localtime()  # 將返回的struct time格式的時間賦給tm
print("{}-{}".format(tm.tm_year, tm.tm_mon))  # 用format輸出年月
print(time.gmtime(time.time() - 8000000))  # 返回utc時間的struc時間對象格式
print(time.asctime(time.localtime()))  # 返回時間格式「Sat Dec 30 17:39:47 2017」
print(time.ctime())  # 返回時間格式「Sat Dec 30 17:41:44 2017」同上

# 日期字符串 轉換 時間戳
string_2_struct = time.strptime("2017/12/30", "%Y/%m/%d")  # 將日期字符串 轉換 struct時間對象格式
print(string_2_struct)

struct_2_stamp = time.mktime(string_2_struct)  # 將struct時間對象轉換成爲時間戳
print(struct_2_stamp)
print(time.ctime(struct_2_stamp))  # 返回時間爲「Sat Dec 30 00:00:00 2017」格式

# 將時間戳轉爲字符串格式
print(time.gmtime(time.time() - 86640))  # 將utc時間戳轉換struct_time格式
print(time.strftime("%Y-%m-%d %H:%M:%S", time.gmtime()))  # 將utc struct_time格式轉換成指定的字符串格式
print(time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()))  # 將本地 struct_time格式轉換成指定的字符串格式

 datetime模塊

import datetime

print(datetime.datetime.now())  # 返回「2017-12-30 17:56:40.261813」
print(datetime.date.fromtimestamp(time.time()))  # 時間戳直接轉換成爲日期格式「2017-12-30」
# 時間加減
print(datetime.datetime.now())
print(datetime.datetime.now() + datetime.timedelta(3))  # 當前時間+3天
print(datetime.datetime.now() + datetime.timedelta(-3))  # 當前時間-3天
print(datetime.datetime.now() + datetime.timedelta(hours=3))  # 當前時間+3小時
print(datetime.datetime.now() + datetime.timedelta(minutes=30))  # 當前時間+30分鐘

c_time = datetime.datetime.now()
# print(c_time.replace(minute=3, hour=2))  # 時間替換,替換小時和分鐘
print(c_time.replace(hour=2, minute=3))  # 時間替換,替換小時和分鐘

 

logging模塊

logging模式是一個日誌模塊,不少程序都須要一個記錄日誌,因此python爲咱們提供了這麼一個模塊,logging的日誌分爲5個等級:debug(),waring(),error(),critical()

日誌等級(數字越大,表示危害越高):

critical = 50

error = 40

warning = 30

info = 20

debug = 10

注意:只有【當前寫等級】大於【日誌等級】時,日誌文件才被記錄

 

日誌輸出,最簡單的用法:

import logging

logging.warning("user [smelond] attempted wrong password more than 3 times")  # 能夠直接輸出到屏幕上
logging.critical("server is down")

 

 將日誌輸出到文件裏面:

import logging
logging.basicConfig(filename='example.log', level=logging.INFO)  # 設置將輸出內容保存到example.log
# level=loggin.INFO意思是,把日誌紀錄級別設置爲INFO,也就是說,只有比日誌是INFO或比INFO級別更高的日誌纔會被紀錄到文件裏
logging.debug("this message should go to the log file")  # 不會保存到日誌文件裏面
logging.info("So should this")  # 日誌級別也爲info,因此能夠保存到文件
logging.warning("And this,too")  # 這個等級大於info,因此也能夠保存到文件裏面

 

將日誌輸出到文件裏面,而且加上時間:

logging.basicConfig(filename='example.log', level=logging.INFO, format="%(asctime)s (message)s", datefmt="%m%d%Y %H:%M:%S %p")  # format格式化輸出,後面放時間格式
# level=loggin.INFO意思是,把日誌紀錄級別設置爲INFO,也就是說,只有比日誌是INFO或比INFO級別更高的日誌纔會被紀錄到文件裏
logging.debug("this message should go to the log file")  # 不會保存到日誌文件裏面
logging.info("So should this")  # 日誌級別也爲info,因此能夠保存到文件
logging.warning("And this,too")  # 這個等級大於info,因此也能夠保存到文件裏面
logging.warning("is when this event was logged.")  # 大於info

輸出:
01012018 20:16:36 PM So should this
01012018 20:16:36 PM And this,too
01012018 20:16:36 PM is when this event was logged.

 

如下來自alex li

日誌輸出格式:

%(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模塊記錄日誌涉及到的四個主要類:

logger提供了應用程序能夠直接使用接口

handler將(logging建立)日誌記錄發送到合適的目的輸出

filter提供了細度設備來決定輸出哪條日誌記錄

formatter決定日誌記錄的最終輸出格式

 

logger
每一個程序在輸出信息以前都要得到一個Logger。Logger一般對應了程序的模塊名,好比聊天工具的圖形界面模塊能夠這樣得到它的Logger:
LOG=logging.getLogger(」chat.gui」)
而核心模塊能夠這樣:
LOG=logging.getLogger(」chat.kernel」)

Logger.setLevel(lel):指定最低的日誌級別,低於lel的級別將被忽略。debug是最低的內置級別,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():能夠設置的日誌級別

 

handler

handler對象負責發送相關的信息到指定目的地。Python的日誌系統有多種Handler可使用。有些Handler能夠把信息輸出到控制檯,有些Logger能夠把信息輸出到文件,還有些 Handler能夠把信息發送到網絡上。若是以爲不夠用,還能夠編寫本身的Handler。能夠經過addHandler()方法添加多個多handler
Handler.setLevel(lel):指定被處理的信息級別,低於lel級別的信息將被忽略
Handler.setFormatter():給這個handler選擇一個格式
Handler.addFilter(filt)、Handler.removeFilter(filt):新增或刪除一個filter對象


每一個Logger能夠附加多個Handler。接下來咱們就來介紹一些經常使用的Handler:
1) logging.StreamHandler
使用這個Handler能夠向相似與sys.stdout或者sys.stderr的任何文件對象(file object)輸出信息。它的構造函數是:
StreamHandler([strm])
其中strm參數是一個文件對象。默認是sys.stderr


2) logging.FileHandler
和StreamHandler相似,用於向一個文件輸出日誌信息。不過FileHandler會幫你打開這個文件。它的構造函數是:
FileHandler(filename[,mode])
filename是文件名,必須指定一個文件名。
mode是文件的打開方式。參見Python內置函數open()的用法。默認是’a',即添加到文件末尾。

3) logging.handlers.RotatingFileHandler
這個Handler相似於上面的FileHandler,可是它能夠管理文件大小。當文件達到必定大小以後,它會自動將當前日誌文件更名,而後建立 一個新的同名日誌文件繼續輸出。好比日誌文件是chat.log。當chat.log達到指定的大小以後,RotatingFileHandler自動把 文件更名爲chat.log.1。不過,若是chat.log.1已經存在,會先把chat.log.1重命名爲chat.log.2。。。最後從新建立 chat.log,繼續輸出日誌信息。它的構造函數是:
RotatingFileHandler( filename[, mode[, maxBytes[, backupCount]]])
其中filename和mode兩個參數和FileHandler同樣。
maxBytes用於指定日誌文件的最大文件大小。若是maxBytes爲0,意味着日誌文件能夠無限大,這時上面描述的重命名過程就不會發生。
backupCount用於指定保留的備份文件的個數。好比,若是指定爲2,當上面描述的重命名過程發生時,原有的chat.log.2並不會被改名,而是被刪除。


4) logging.handlers.TimedRotatingFileHandler
這個Handler和RotatingFileHandler相似,不過,它沒有經過判斷文件大小來決定什麼時候從新建立日誌文件,而是間隔必定時間就 自動建立新的日誌文件。重命名的過程與RotatingFileHandler相似,不過新的文件不是附加數字,而是當前時間。它的構造函數是:
TimedRotatingFileHandler( filename [,when [,interval [,backupCount]]])
其中filename參數和backupCount參數和RotatingFileHandler具備相同的意義。
interval是時間間隔。
when參數是一個字符串。表示時間間隔的單位,不區分大小寫。它有如下取值:
S 秒
M 分
H 小時
D 天
W 每星期(interval==0時表明星期一)
midnight 天天凌晨

 

將日誌文件輸出到多個地方:

# 將日誌輸出到多個地方
import logging

# create logger
logger = logging.getLogger('TEST-LOG')  # 設置一個名稱
logger.setLevel(logging.INFO)  # 設置一個最低日誌輸出等級,設置爲了INFO等級,(全局)

# create console handler and set level to debug
ch = logging.StreamHandler()  # 輸出到屏幕上
ch.setLevel(logging.DEBUG)  # 設置屏幕輸出的最低日誌等級可是會發現不能輸出debug,由於咱們上面的全局配置上最低設置成爲了INFO等級,DEBIG>INFO

# create file handler and set level to warning
fh = logging.FileHandler("access.log")  # 設置輸出到文件
fh.setLevel(logging.WARNING)  # 設置文件輸出的最低等級
# create formatter
formatter_ch = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')  # 格式化
formatter_fh = logging.Formatter('%(asctime)s  - %(levelname)s - %(message)s')  # 格式化

# add formatter to ch and fh
ch.setFormatter(formatter_ch)  # 設置輸出到屏幕上的格式
fh.setFormatter(formatter_fh)  # 設置輸出到日誌中的格式

# add ch and fh to logger
logger.addHandler(ch)  # 添加handler
logger.addHandler(fh)

# 'application' code
logger.debug('debug message')  # 輸出提示(不能輸出到任何地方)
logger.info('info message')  # 輸出提示(只能輸出到屏幕,由於輸出到文件最低等級須要WARNING)
logger.warning('warn message')  # 輸出提示(雙方)
logger.error('error message')  # 雙方
logger.critical('critical message')  # 雙方


屏幕輸出:
2018-01-02 11:44:34,121 - TEST-LOG - INFO - info message
2018-01-02 11:44:34,121 - TEST-LOG - WARNING - warn message
2018-01-02 11:44:34,121 - TEST-LOG - ERROR - error message
2018-01-02 11:44:34,121 - TEST-LOG - CRITICAL - critical message

文件輸出:
2018-01-02 11:44:34,121  - WARNING - warn message
2018-01-02 11:44:34,121  - ERROR - error message
2018-01-02 11:44:34,121  - CRITICAL - critical message
相關文章
相關標籤/搜索