常用內建模組

92

Upload: justin-lin

Post on 14-Apr-2017

416 views

Category:

Software


0 download

TRANSCRIPT

11. 常用內建模組

• 學習目標

– 處理日期與時間

– 認識日誌的使用

– 運用規則表示式

– 管理檔案與目錄

時間的度量

• 格林威治標準時間

–經常簡稱 GMT 時間

–常不嚴謹(且有爭議性)地當成是 UTC 時間

• 世界時

–藉由觀測遠方星體跨過子午線而得

–在 1972 年導入 UTC 之前,GMT 與 UT 是相同的

• 國際原子時

–將秒的國際單位(International System of Units, SI)定義為銫(caesium)原子輻射振動 9192631770 周耗費的時間

–時間從 UT 的 1958 年開始同步

• 世界協調時間

–折衷修正版本的世界協調時間,常簡稱為 UTC

– 1972 年 UTC採用了閏秒(leap second)修正

• Unix 時間

– UTC 時間 1970 年(Unix 元年)1 月1 日 00:00:00 為起點而經過的秒數

–不考慮閏秒修正,用以表達時間軸上某一瞬間

• epoch

–某個特定時間的起點,時間軸上某一瞬間

– Unix epoch 選為UTC 時間 1970 年 1 月 1 日00:00:00

• 就目前來說,即使標註為 GMT,實際上談到時間指的是UTC 時間

• 秒的單位定義是基於 TAI,也就是銫原子輻射振動次數

• UTC 考量了地球自轉越來越慢而有閏秒修正

• Unix 時間是 1970 年 1 月 1 日 00:00:00 為起點而經過的秒數,不考慮閏秒

年曆與時區簡介

• 儒略曆

–修正了羅馬曆隔三年設置一閏年的錯誤,改採四年一閏

• 格里高利曆

–改革了儒略曆

–將儒略曆 1582 年 10 月 4 日星期四的隔天,訂為格里高利曆 1582 年 10 月 15 日星期五

–各個國家改曆的時間並不相同

• ISO8601 標準

–嚴格來說並非年曆系統,而是時間日期表示方法的標準,用以統一時間日期的資料交換格式

– 19 世紀是指 1900 至 1999 年(包含該年),而格里高利曆的 19 世紀是指 1801 年至 1900 年(包含該年)

時區

• 各種時間日期的議題中最複雜的

• 牽涉到地理、法律、經濟、社會甚至政治等問題

• UTC 偏移(offset)

–大致上來說,經度每 15 度是偏移一小時

–通常會在時間的最後標識 Z 符號

–有些國家的領土橫跨的經度很大,一個國家有多個時間反而造成困擾,因而不採取每 15 度偏移一小時的作法

• 日光節約時間

–也稱為夏季時間(Summer time)

–有些高緯度國家,夏季、冬季日照時間差異很大,為了節省能源會儘量利用夏季日照

–台灣也曾實施過日光節約時間,後來因為沒太大實質作用而取消

• 如果想獲取系統的時間,Python 的 time

模組提供了一層介面,用來呼叫各平台上的C 程式庫函式,它提供的相關函式,通常與 epoch 有關

• gmtime() 傳回了 struct_time 實例

• time.gmtime(0) 表示從 epoch 起算經

過了 0 秒

• 如果不指定數字,表示取得目前的時間並傳回 struct_time 實例

• UTC 是一種絕對時間,與時區無關,也沒有日光節約時間的問題

• time.time() 傳回的是浮點數

• time 模組提供的是低階的機器時間觀點,

也就是從 epoch 起經過的秒數

• 有些輔助函式,可以作些簡單的轉換,以便成為人類可理解的時間概念

• localtime()則可提供目前所在時間

• 有個代表時間的字串,想要將其剖析為 struct_time 實例,可以使用 strptime() 函式

• 如果你有個 struct_time 物件,想要轉

換為從 epoch 起經過之秒數,可以使用mktime()

• ctime(secs) 是 asctime(localtime(secs))的封裝

• asctime() 可指定 struct_time 實例,

取得一個簡單的時間字串描述

• strftime() 接受一個格式指定與 struct_time 實例

• time 模組提供的終究是低階的機器時間觀

點,用來表示人類可理解的時間概念並不方便

• 若想從人類的觀點來表示時間,可以進一步使用 datetime 模組

使用 datetime 模組

• 人類在時間的表達上有時只需要日期、有時只需要時間,有時會同時表達日期與時間

• 通常不會特別聲明時區

• 可能只會提及年、月、年月、月日、時分秒等

• 對於人類時間表達,datetime 模組提供

–datetime(包括日期與時間)

–date(只有日期)

–time(只有時間)

• 有個 datetime 或 date 實例,想將它們包含的時間概念轉換為 UTC 時間戳記

• 有個時間戳記,也可以透過 datetime 或date 的 fromtimestamp() 來建立 datetime 或 date 實例

• datetime、date、time 實例都有個 isoformat() 方法,可傳回時間字串描述

• 採用的是 ISO8601 標準,當日期與時間同時表示時,預設會使用 T 來分隔,若必要也可以自行指定

• datetime 類別的 strptime() 類別方法,會傳回 datetime 實例

• 如果需要進行日期或時間的運算,可以使用 datetime 的 timedelta 類別方法

• 想知道加上 3 週又 5 天 8 小時35 分鐘後的日期時間是什麼?

• 2014 年 2 月 21 日加 9 天會是幾月幾號?

• datetime 實例本身預設並沒有時區資訊,

此時單純表示本地時間

• datetime 類別上的 tzinfo 類別,可以繼

承以實作時區的相關資訊與操作

• 從 Python 3.2 開始,datetime 類別新增了timezone 類別,它是 tzinfo 的子類

別,用來提供基本的 UTC 偏移時區實作

• 想將 utc 轉換為台灣的時區

• 內建的 timezone 只單純考量了UTC 偏移,

不考量日光節約時間等其他因素

• 若需要 timezone 以外的其他時區定義,可以額外安裝社群貢獻的 pytz 模組

• 可以使用 pip install pytz 來安裝

• pytz 的 timezone 也可以解決棘手的日

光節約時間問題

• 在台灣時區, 1975 年 3 月 31 日 23 時 40 分 0 秒加一個小時的時間會是多少呢?

• 使用了 normalize() 之後,才能得到考

量了日光節約時間的正確時間

• 一個常見的建議是,使用 UTC 來進行時間的儲存或操作

• 因為UTC 是絕對時間,不考量日光節約時間等問題

• 在必須使用當地時區的場合時,再使用 datetime 實例的 astimezone() 做轉換

日誌

• 一般來說,一個模組只需要一個 Logger

實例

• 建議透過 logging.getLogging() 來取得 Logger 實例

• 呼叫 getLogger() 時,可以指定名稱,相同名稱下取得的 Logger 會是同一實例

• 呼叫 getLogger() 時可以不指定名稱,這時會取得根 Logger

• 父階層相同的 Logger,父 Logger 的組

態相同

• 想要套件中的模組在進行日誌時,都使用相同的父組態,可以在套件的 __init__.py 檔案中撰寫:

• Logger 有階層關係

• 每個 Logger 處理完自己的日誌動作後,會再委託父 Logger 處理

• 在不調整父 Logger 組態的情況下,直接設定 Logger 實例,就只能設定為更嚴格

的日誌層級,才會有實際的效用

• 如果想要調整根 Logger 的組態,可以使用 logging.basicConfig()

• 根 Logger 的日誌訊息預設會輸出至sys.stderr

• 想要修改能輸出至檔案,可以使用 logging.basicConfig() 指定 filename 參數

• 子 Logger 實例可以透過 addHandler()

新增自己的處理器

• 若要自訂格式,可以透過 logging.Formatter() 建立 Formatter 實例, 再透過處理器的 setFormatter() 設定

• 定義過濾器可以繼承 logging.Filter 類別並定義 filter(record) 方法

• 或者是定義一個物件具有 filter(record) 方法

• 自 Python 3.2 之後,也可以使用函式作為過濾器了

• Logger 或 Handler 實例都有 addFilter() 方法,可以新增過濾器

使用 logging.config

• 在 Python 的 logging 模組官方文件中有

個範例

• 自 Python 3.2 開始,建議改用 logging.config.dictConfig()

簡介規則表示式

• 想根據某個字元或字串切割,可以使用str 的 split()

• 如果切割字串的依據不單只是某個字元或子字串,而是任意單一數字呢?

• 使用 re 模組來支援規則表示式

• 因為 \ 在Python 字串中被作為轉義字元,

因此要撰寫規則表示式時,必須撰寫為 '\\d'

• 在撰寫規則表示式時,建議使用原始字串

• 規則表示式基本上包括兩種字元:

–字面字元(Literals)

–詮譯字元(Metacharacters)

• 字面字元是指按照字面意義比對的字元

• 詮譯字元是不按照字面比對,在不同情境有不同意義的字元

• 找出並理解詮譯字元想要詮譯的概念,對於規則表示式的閱讀非常重要

• 字母和數字在規則表示式中,都是按照字面意義比對

• 有些字元之前加上了 \ 之後,會被當作詮

譯字元

• 詮譯字元在規則表示式中有特殊意義,例如! $ ^ * ( ) + = { } [ ] |

\ : . ?等

• 若要比對這些字元,則必須加上忽略符號

• 如果不確定哪些標點符號字元要加上忽略符號,可以在每個標點符號前加上 \,例如比對逗號也可以寫 \,

• 如果規則表示式為 XY,那麼表示比對「X 之後要跟隨著 Y」

• 如果想表示「X 或 Y」,可以使用 X|Y

• 如果有多個字元要以「或」的方式表示,例如「X 或 Y 或 Z」,則可以使用字元類表示為[XYZ]

• 規則表示式中,多個字元可以歸類在一起,成為一個字元類(Character class)

• 字元類會比對文字中是否有「任一個」字元符合字元類中某個字元

• 規則表示式中被放在 [] 中的字元就成為一

個字元類

• | 在字元類別只是個普通字元,不會被當作

「或」來表示

• 字元類中可以使用連字號 - 作為字元類詮譯字元,表示一段文字範圍

• 字元類中可以使用 ^ 作為字元類詮譯字元, [^] 則為反字元類(Negated character

class)

• 貪婪量詞會儘可能地找出長度最長的符合文字

• 在貪婪量詞表示法後加上? , 將會成為逐步量詞( Reluctant quantifier)

• 逐步量詞會儘可能地找出長度最短的符合文字

• 有個文字Justin dog Monica doggie Irene,你想要直接依當中單字 dog 切出前後兩個子字串?

• 可以使用 \b 標出單字邊界

• 可以使用 () 來將規則表示式分組,除了作

為子規則表示式之外,還可搭配量詞使用

• 例如想要驗證電子郵件格式,域名稱可以有數層,必須是大小寫英文字元或數字 – ^[a-zA-Z]+\d*@([a-zA-Z0-9]+\.)+com

• 被分組的規則表示式,還可以在稍後回頭參考(Back reference)

• 如果有個規則表示式 ((A)(B(C))),其中

有四個分組

• 分組回頭參考時,是在 \ 後加上分組計數,

表示參考第幾個分組的比對結果

• \d\d 要求比對兩個數字,(\d\d)\1 的話,

表示要輸入四個數字,輸入的前兩個數字與後兩個數字必須相同

• ["'][^"']*["'] 比對單引號或雙引號中

0 或多個字元,但沒有比對兩個都要是單引號或雙引號

• (["'])[^"']*\1 則比對出前後引號必須

一致

Pattern 與 Match 物件

• 剖析、驗證規則表示式往往是最耗時間的階段

• 在頻繁使用某規則表示式的場合,若可以將剖析、驗證過後的規則表示式重複使用,對效率將會有所幫助

• re.compile() 可以建立規則表示式物件,

在剖析、驗證過規則表示式無誤後傳回的規則表示式物件可以重複使用

• 可以指定 flags 參數,進一步設定規則表

示式物件的行為

• 也可以在規則表示式中使用嵌入旗標表示法( Embedded Flag Expression)

• 例如 re.IGNORECASE 等效的嵌入旗標表示法為 (?i),以下片段效果等同上例:

• 可以使用 finditer()方法,它會傳回一

個 iterable 物件,每一次迭代都會得到一個 Match 物件

• search() 方法與 match() 方法必須小心區分,search() 會在整個字串中,

• 找尋第一個符合的子字串,而 match() 只

會在字串開頭看看接下來的字串是否符合

• 如果規則表示式中設定了分組,findall() 方法會以清單傳回各個分組

• 如果想要取得 1212、4545、9999 這樣的結果,要使用 finditer() 方法

• 若想找出單引號或雙引號中的文字,如下使用 findall() 是行不通的:

• 如果要找出單引號或雙引號中的文字,必須如下:

• 也可以使用 group() 指定數字,表示要取得哪個分組,或者是使用 groups() 傳回一個 tuple,其中包含符合的分組

• 如果要取代符合的子字串,可以使用規則表示式物件的 sub()方法

• 如果規則表示中有分組設定,在使用 sub() 時,可以使用 \num 來捕捉被分組匹配的文

取得目錄資訊

• 若想知道目前工作目錄,或者切換工作目錄,可以使用 os.getcwd() 或 os.chdir():

• 如果想得知指定的目錄下,有哪些檔案或目錄,可以使用 os.listdir()

• 如果想要以惰性的方式處理,可以使用 os.scandir()

• 走訪目錄

• os.walk()會自行走訪子目錄

建立、修改、移除目錄

• 如果是有關於路徑的操作,Python 提供了 os.path 模組來解決相關的需求

–路徑的組合

–相對路徑轉為絕對路徑

–取得檔案所在的目錄路徑等

–路徑對應的檔案目或目錄資訊

• 想在工作目錄下搜尋檔案,例如想搜尋.py 檔案,可以使用 glob 模組

• glob 是個很簡單的模組,支援簡易的Glob

模式比對語法

• 比規則表示式簡單,常用於目錄與檔案名稱的比對