豬行天下之Python基礎——10.1 Python常用模組(上)

coder-pig發表於2019-04-19

內容簡述:

  • 1、time和datetime模組
  • 2、logging模組

PS:如果你想搜尋安裝某個模組或者釋出一個自己的模組可以到移步到:pypi.org/


1、time和datetime時間模組


① 基本操作

程式碼示例如下

import time, datetime

# 獲取當前時間
moment = time.localtime()
print("年:%s" % moment[0])
print("月:%s" % moment[1])
print("日:%s" % moment[2])
print("時:%s" % moment[3])
print("分:%s" % moment[4])
print("秒:%s" % (moment[5] + 1))
print("周幾:%s" % (moment[6] + 1))
print("一年第幾天:%s" % moment[7])
print("是否為夏令時:%s" % moment[8], end="\n\n")

# 格式化時間(這裡要注意strftime和strptime是不一樣的!!!)
moment1 = time.strftime('%Y-%m-%d %H:%M:%S')
moment2 = time.strftime('%a %b %d %H:%M:%S %Y', time.localtime())
moment3 = time.mktime(time.strptime(moment2, '%a %b %d %H:%M:%S %Y'))
print(moment1)
print(moment2)
print(moment3, end="\n\n")

# 獲得當前時間戳
print(time.time())  # 秒級
print(int(round(time.time() * 1000)), end="\n\n")  # 毫秒級

# 獲得當前時間(時間陣列,還需strftime格式化下)
print(datetime.datetime.now(), end="\n\n")

# 時間戳轉換為時間
# 方法一:
moment4 = 1512184082
moment5 = time.localtime(moment4)  # 轉換成時間陣列
print(time.strftime('%Y-%m-%d %H:%M:%S', moment5), end="\n\n")  # 格式化

# 方法二:
moment6 = datetime.datetime.utcfromtimestamp(moment4)
print(moment6)
moment7 = moment6.strftime('%a %b %d %H:%M:%S %Y')
print(moment7, end="\n\n")

# 程式碼延遲執行
time.sleep(5)
複製程式碼

執行結果如下

年:2019
月:3
日:14
時:11
分:41
秒:57
周幾:4
一年第幾天:73
是否為夏令時:0

2019-03-14 11:41:56
Thu Mar 14 11:41:56 2019
1552534916.0

1552534916.3338902
1552534916334

2019-03-14 11:41:56.333890

2017-12-02 11:08:02

2017-12-02 03:08:02
Sat Dec 02 03:08:02 2017
複製程式碼

② struct_time,字串,時間戳之間的轉換關係


③ Python中的時間日期格式化符號

如下表所示,參考時間為(20190314 13:53:41)

符號 描述 示例
%y 兩位數的年份表示(00-99) 19
%Y 四位數的年份表示(000-9999) 2019
%m 月份(01-12) 03
%d 月內中的一天(0-31) 14
%H 24小時制小時數(0-23) 13
%I 12小時制小時數(01-12) 01
%M 分鐘數(00=59) 53
%S 秒(00-59) 41
%a 星期幾的英文簡寫 Thu
%A 星期幾的英文 Thursday
%b 月份的英文簡寫 Mar
%B 月份的英文 March
%x 日期 03/14/19
%X 時間 13:59:04
%c 日期和時間 Thu Mar 14 13:54:56 2019
%j 一年中第幾天 073
%p 以AM和PM的方式顯示上午還是下午 PM
%U 一年中的第幾周,周天為一週的第一天 10
%W 一年中的第幾周,週一為一週的第一天 10
%w 一週中的第幾天,周天為0,週一為1 4
%z,%Z 當前時區的名稱
%% %號自身 %

④ 一些實用的程式碼片段

下面提供一些很實用的程式碼片段,用到的時候複製貼上即可:

import datetime
import time

now = datetime.datetime.now()


# 獲得當前時間的前/後幾天,幾小時,幾秒,毫秒
# 如果是想獲得時間戳可以直接呼叫int(time.mktime(求出來的時間.timetuple()))
def fetch_before_time(time_type, value, strf="%Y-%m-%d %H:%M:%S"):
    if time_type == 'days':
        if value > 0:
            return (datetime.datetime.now() + datetime.timedelta(days=value)).strftime(strf)
        else:
            return (datetime.datetime.now() - datetime.timedelta(days=value)).strftime(strf)
    elif time_type == 'hours':
        if value > 0:
            return (datetime.datetime.now() + datetime.timedelta(hours=value)).strftime(strf)
        else:
            return (datetime.datetime.now() - datetime.timedelta(hours=value)).strftime(strf)
    elif time_type == 'seconds':
        if value > 0:
            return (datetime.datetime.now() + datetime.timedelta(seconds=value)).strftime(strf)
        else:
            return (datetime.datetime.now() - datetime.timedelta(seconds=value)).strftime(strf)
    elif time_type == 'microseconds':
        if value > 0:
            return (datetime.datetime.now() + datetime.timedelta(microseconds=value)).strftime(strf)
        else:
            return (datetime.datetime.now() - datetime.timedelta(microseconds=value)).strftime(strf)


# 獲得第二天凌晨的時間戳
def fetch_morning_timestamp():
    return int(time.time()) + (144000 - (int(time.time())) % 86400)


# 構造一個由起始事件到結束時間間所有的日期列表
def init_date_list(begin_date, end_date):
    date_list = []
    begin_date = datetime.datetime.strptime(str(begin_date), "%Y%m%d")
    end_date = datetime.datetime.strptime(str(end_date), "%Y%m%d")
    while begin_date <= end_date:
        date_str = begin_date.strftime("%Y%m%d")
        date_list.append(date_str)
        begin_date += datetime.timedelta(days=1)
    return date_list


if __name__ == '__main__':
    print("當前時間:", datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S"))
    print(fetch_before_time('days'3))
    print(fetch_before_time('hours', -3))
    print(fetch_before_time('seconds'3))
    print("第二天早上的時間戳:", fetch_morning_timestamp())
    print("從20190101到20190301的日期列表:%s" % init_date_list(2019010120190301))
複製程式碼

執行結果如下

當前時間: 2019-03-14 15:44:58
2019-03-17 15:44:58
2019-03-14 18:44:58
2019-03-14 15:45:01
第二天早上的時間戳: 1552665600
從20190101到20190301的日期列表:['20190101', '20190102',...過長省略... '20190226', '20190227', '20190228', '20190301']
複製程式碼

2、logging日誌模組

大部分的程式都會有「記錄執行日誌的需求」,而日誌資訊一般有這樣幾類:正常的程式執行日誌除錯錯誤或警告資訊的輸出等。而日常開發中我們需要把日誌持久化到本地,進行一些觀察和統計,錯誤排查等,如果只用print函式輸出的話,顯然有點捉襟見寸。在Python內建了一個日誌模組:logging,它提供了標準的日誌介面,支援日誌分級和儲存


① 日誌分級

在開始正式學習logging前,我們先了解下「日誌分級」,即:什麼時候用什麼等級的日誌。如下表所示:

級別 建議什麼時候使用
DEBUG 詳細的資訊,常用於問題診斷
INFO 記錄關鍵節點資訊,用於確認程式是否按照預期執行
WARNING 程式還是正常執行,但某些不期望的事情發生時記錄的資訊(如磁碟可用空間較低)
ERROR 由於更嚴重的問題導致某些功能不能正常執行時記錄的資訊
CRITICAL 發生嚴重錯誤,導致程式不能繼續執行時記錄的資訊

列印各種級別的程式碼示例如下:

import logging

if __name__ == '__main__':
    # 獲得一個Logger
    logger = logging.getLogger("Test")

    # logging提供的簡單的配置方法,自行配置的話需要手動新增handler
    logging.basicConfig()

    # 設定輸出的log級別(大於或等於此級別的才會輸出),預設級別Warning
    logger.setLevel(logging.INFO)
    logger.debug("=== Debug 級別的資訊 ==="# 不會輸出
    logger.info("=== Info 級別的資訊 ===")
    logger.warning("=== Warning 級別的資訊 ===")
    logger.error("=== Error 級別的資訊 ===")
    logger.critical("=== Critical 級別的資訊 ===")
複製程式碼

執行結果如下

INFO:Test:=== Info 級別的資訊 ===
WARNING:Test:=== Warning 級別的資訊 ===
ERROR:Test:=== Error 級別的資訊 ===
CRITICAL:Test:=== Critical 級別的資訊 ===
複製程式碼

② 將日誌寫入到檔案

日誌預設是輸出到Console(螢幕)上,如果我們想把詳細的日誌輸出到log檔案裡,則需要用到handler了,理論上可以把日誌輸出到各種流中stderr檔案socket等都可以,在logging中已經將各種流handler封裝好了,你也可以繼承StreamHandler類自己做一些定製,簡單的把日誌寫入到檔案中的程式碼示例如下:

import logging

if __name__ == '__main__':
    logger = logging.getLogger("Test")
    logger.setLevel(logging.INFO)
    # 輸出到控制檯
    logger.addHandler(logging.StreamHandler())
    # 輸出到檔案
    logger.addHandler(logging.FileHandler('test.log', encoding='UTF-8'))
    logger.debug("=== Debug 級別的資訊 ===")
    logger.info("=== Info 級別的資訊 ===")
    logger.warning("=== Warning 級別的資訊 ===")
    logger.error("=== Error 級別的資訊 ===")
    logger.critical("=== Critical 級別的資訊 ===")
複製程式碼

執行結果如下(同時在目錄下生成了一個test.log的檔案):

=== Info 級別的資訊 ===
=== Warning 級別的資訊 ===
=== Error 級別的資訊 ===
=== Critical 級別的資訊 ===
複製程式碼

嗯,你可能有這樣的需求,Console列印Warning以上的日誌,而log檔案儲存Debug級別以上的日誌,那麼可以修改下上面的程式碼,修改後的程式碼如下:

if __name__ == '__main__':
    logger = logging.getLogger("Test")
    logger.setLevel(logging.INFO)

    # 輸出到控制檯
    s_handler = logging.StreamHandler()
    s_handler.setLevel(logging.WARNING)
    logger.addHandler(s_handler)

    # 輸出到檔案
    f_handler = logging.FileHandler('test.log', encoding='UTF-8')
    f_handler.setLevel(logging.DEBUG)
    logger.addHandler(f_handler)
    logger.debug("=== Debug 級別的資訊 ===")
    logger.info("=== Info 級別的資訊 ===")
    logger.warning("=== Warning 級別的資訊 ===")
    logger.error("=== Error 級別的資訊 ===")
    logger.critical("=== Critical 級別的資訊 ===")
複製程式碼

執行結果如下

# 控制檯輸出:
=== Warning 級別的資訊 ===
=== Error 級別的資訊 ===
=== Critical 級別的資訊 ===

# test.log檔案:
=== Info 級別的資訊 ===
=== Warning 級別的資訊 ===
=== Error 級別的資訊 ===
=== Critical 級別的資訊 ===
複製程式碼

③ 定製日誌輸出格式

糾結完輸出到那裡,接著就輸出日誌的格式了,日誌一般都是比較規範的,比如日誌列印的時間型別等,而不會像我們這樣隨意拼接一段字串,對於日誌格式的定製可以通過logging模組Formatter元件來定製。basicConfig()中的handler 自帶一個formatter,通過logging.basicConfig(**kwargs)函式進行定製,該函式可接收的關鍵字引數如下表所示。

引數 描述
filename 指定日誌輸出目標檔案的檔名,設定後資訊就不會列印到控制檯
filemode 指定日誌檔案的開啟模式,預設為'a',設定了filename這個才會生效
format 指定日誌格式字串,即指定日誌輸出時所包含的欄位資訊以及它們的順序
datefmt 指定日期/時間格式,該選項要在format中包含時間欄位%(asctime)s時才有效
level 指定日誌器的日誌級別
stream 指定日誌輸出目標stream,不能和filename同時使用否則會引起ValueError異常
style Python 3.2新增,預設'%'指定format格式字串的風格,可取值為'%'、'{'和'$'

format格式字串的欄位列表如下表所示:

引數 描述
%(asctime)s 日誌發生的時間--人類可讀時間,如:2003-07-08 16:49:45,896
%(created)f 日誌發生的時間--時間戳,就是當時呼叫time.time()函式返回的值
%(relativeCreated)d 日誌發生的時間相對於logging模組載入時間的相對毫秒數
%(msecs)d 日誌發生時間的毫秒部分
%(levelname)s 該日誌記錄的文字形式的日誌級別('DEBUG', 'INFO', 'WARNING',
'ERROR', 'CRITICAL')
%(levelno)s 該日誌記錄的數字形式的日誌級別(10, 20, 30, 40, 50)
%(name)s 所使用的日誌器名稱,預設是'root',因為預設使用的是 rootLogger
%(message)s 日誌記錄的文字內容,通過 msg % args計算得到的
%(pathname)s 呼叫日誌記錄函式的原始碼檔案的全路徑
%(filename)s pathname的檔名部分,包含檔案字尾
%(module)s filename的名稱部分,不包含字尾
%(lineno)d 呼叫日誌記錄函式的原始碼所在的行號
%(funcName)s 呼叫日誌記錄函式的函式名
%(process)d 程式ID
%(processName)s 程式名稱,Python 3.1新增
%(thread)d 執行緒ID
%(thread)s 執行緒名稱

簡單的使用程式碼示例如下

import logging

if __name__ == '__main__':
    logger = logging.getLogger("Test")
    logging.basicConfig(level=logging.INFO,
                        format="%(asctime)s %(process)d:%(processName)s- %(levelname)s === %(message)s",
                        datefmt="%Y-%m-%d %H:%M:%S %p")

    logger.debug("Debug 級別的資訊")
    logger.info("Info 級別的資訊")
    logger.warning("Warning 級別的資訊")
    logger.error("Error 級別的資訊")
    logger.critical("Critical 級別的資訊")
複製程式碼

執行結果如下

2019-03-14 16:39:02 PM 8628:MainProcess- INFO === Info 級別的資訊
2019-03-14 16:39:02 PM 8628:MainProcess- WARNING === Warning 級別的資訊
2019-03-14 16:39:02 PM 8628:MainProcess- ERROR === Error 級別的資訊
2019-03-14 16:39:02 PM 8628:MainProcess- CRITICAL === Critical 級別的資訊
複製程式碼

另外要注意一點basicConfig沒有設定編碼的屬性,如果想把日誌寫入到檔案裡,而日誌裡又有中文的話,只能通過一開始那種設定FileHandler物件的方式!除了通過basicConfig()設定日誌格式,還可以自定義一個Formatter物件,然後呼叫setFormatter函式進行設定。使用程式碼示例如下:

import logging

if __name__ == '__main__':
    logger = logging.getLogger("Test")
    logger.setLevel(logging.INFO)
    # 自定義Formatter物件
    fmt = logging.Formatter("%(asctime)s %(process)d:%(processName)s- %(levelname)s === %(message)s",
                            datefmt="%Y-%m-%d %H:%M:%S %p")
    # 輸出到控制檯
    s_handler = logging.StreamHandler()
    s_handler.setLevel(logging.WARNING)
    s_handler.setFormatter(fmt)
    logger.addHandler(s_handler)
    # 輸出到檔案
    f_handler = logging.FileHandler('test.log', encoding='UTF-8')
    f_handler.setLevel(logging.DEBUG)
    f_handler.setFormatter(fmt)
    logger.addHandler(f_handler)
    logger.debug("Debug 級別的資訊")
    logger.info("Info 級別的資訊")
    logger.warning("Warning 級別的資訊")
    logger.error("Error 級別的資訊")
    logger.critical("Critical 級別的資訊")
複製程式碼

執行結果如下

# 控制檯輸出:
2019-03-14 16:41:09 PM 11312:MainProcess- WARNING === Warning 級別的資訊
2019-03-14 16:41:09 PM 11312:MainProcess- ERROR === Error 級別的資訊
2019-03-14 16:41:09 PM 11312:MainProcess- CRITICAL === Critical 級別的資訊

# test.log檔案:
2019-03-14 16:41:09 PM 11312:MainProcess- INFO === Info 級別的資訊
2019-03-14 16:41:09 PM 11312:MainProcess- WARNING === Warning 級別的資訊
2019-03-14 16:41:09 PM 11312:MainProcess- ERROR === Error 級別的資訊
2019-03-14 16:41:09 PM 11312:MainProcess- CRITICAL === Critical 級別的資訊
複製程式碼

logging除了HandlerFormatter兩個元件外還有,FilterLoggerAdapter元件,不過用得
不多,有興趣的同學可以自行到官方文件進行查閱:docs.python.org/3/library/l…


如果本文對你有所幫助,歡迎
留言,點贊,轉發
素質三連,謝謝?~


相關文章