天天看點

第26天:Python 标準庫之 os 子產品詳解

by 軒轅禦龍

<code>os</code>就是“operating system”的縮寫,顧名思義,<code>os</code>子產品提供的就是各種 Python 程式與作業系統進行互動的接口。通過使用<code>os</code>子產品,一方面可以友善地與作業系統進行互動,另一方面頁可以極大增強代碼的可移植性。如果該子產品中相關功能出錯,會抛出<code>OSError</code>異常或其子類異常。

注意,如果是讀寫檔案的話,建議使用内置函數<code>open()</code>;如果是路徑相關的操作,建議使用<code>os</code>的子子產品<code>os.path</code>;如果要逐行讀取多個檔案,建議使用<code>fileinput</code>子產品;要建立臨時檔案或路徑,建議使用<code>tempfile</code>子產品;要進行更進階的檔案和路徑操作則應當使用<code>shutil</code>子產品。

當然,使用<code>os</code>子產品可以寫出作業系統無關的代碼并不意味着<code>os</code>無法調用一些特定系統的擴充功能,但要切記一點:一旦這樣做就會極大損害代碼的可移植性。

此外,導入<code>os</code>子產品時還要小心一點,千萬不要為了圖調用省事兒而将<code>os</code>子產品解包導入,即不要使用<code>from os import *</code>來導入<code>os</code>子產品;否則<code>os.open()</code>将會覆寫内置函數<code>open()</code>,進而造成預料之外的錯誤。

注意,<code>os</code>子產品中大多數接受路徑作為參數的函數也可以接受“檔案描述符”作為參數。 檔案描述符:file descriptor,在 Python 文檔中簡記為 fd,是一個與某個打開的檔案對象綁定的整數,可以了解為該檔案在系統中的編号。

該屬性寬泛地指明了目前 Python 運作所在的環境,實際上是導入的作業系統相關子產品的名稱。這個名稱也決定了子產品中哪些功能是可用的,哪些是沒有相應實作的。

目前有效名稱為以下三個:<code>posix</code>,<code>nt</code>,<code>java</code>。

其中<code>posix</code>是 Portable Operating System Interface of UNIX(可移植作業系統接口)的縮寫。Linux 和 Mac OS 均會傳回該值;<code>nt</code>全稱應為“Microsoft Windows NT”,大體可以等同于 Windows 作業系統,是以 Windows 環境下會傳回該值;<code>java</code>則是 Java 虛拟機環境下的傳回值。

是以在我的電腦(win10)上執行下述代碼,傳回值是<code>nt</code>:

而在 WSL(Windows Subsystem Linux,Windows 下的 Linux 子系統)上的結果則是:

檢視<code>sys</code>子產品中的<code>sys.platform</code>屬性可以得到關于運作平台更詳細的資訊,在此不再贅述

<code>os.environ</code>屬性可以傳回環境相關的資訊,主要是各類環境變量。傳回值是一個映射(類似字典類型),具體的值為第一次導入<code>os</code>子產品時的快照;其中的各個鍵值對,鍵是環境變量名,值則是環境變量對應的值。在第一次導入<code>os</code>子產品之後,除非直接修改<code>os.environ</code>的值,否則該屬性的值不再發生變化。

比如其中鍵為“HOMEPATH”(Windows 下,Linux 下為“HOME”)的項,對應的值就是使用者主目錄的路徑。Windows 下,其值為:

Linux 下,其值為:

這個函數需要傳入一個路徑作為<code>top</code>參數,函數的作用是在以<code>top</code>為根節點的目錄樹中遊走,對樹中的每個目錄生成一個由<code>(dirpath, dirnames, filenames)</code>三項組成的三元組。

其中,<code>dirpath</code>是一個訓示這個目錄路徑的字元串,<code>dirnames</code>是一個<code>dirpath</code>下子目錄名(除去<code>“.”</code>和<code>“..”</code>)組成的清單,<code>filenames</code>則是由<code>dirpath</code>下所有非目錄的檔案名組成的清單。要注意的是,這些名稱并不包含所在路徑本身,要擷取<code>dirpath</code>下某個檔案或路徑從<code>top</code>目錄開始的完整路徑,需要使用<code>os.path.join(dirpath, name)</code>。

注意最終傳回的結果是一個疊代器,我們可以使用<code>for</code>語句逐個取得疊代器的每一項:

第26天:Python 标準庫之 os 子產品詳解

“listdir”即“list directories”,列出(目前)目錄下的全部路徑(及檔案)。該函數存在一個參數,用以指定要列出子目錄的路徑,預設為<code>“.”</code>,即“目前路徑”。

函數傳回值是一個清單,其中各元素均為字元串,分别是各路徑名和檔案名。

通常在需要周遊某個檔案夾中檔案的場景下極為實用。

比如定義以下函數:

該函數的傳回值就是目前目錄下所有檔案而非檔案夾的名稱清單。

“mkdir”,即“make directory”,用處是“建立一個路徑”。需要傳入一個類路徑參數用以指定建立路徑的位置和名稱,如果指定路徑已存在,則會抛出<code>FileExistsError</code>異常。

該函數隻能在已有的路徑下建立一級路徑,否則(即建立多級路徑)會抛出<code>FileNotFoundError</code>異常。

相應地,在需要建立多級路徑的場景下,可以使用<code>os.makedirs()</code>來完成任務。函數<code>os.makedirs()</code>執行的是遞歸建立,若有必要,會分别建立指定路徑經過的中間路徑,直到最後建立出末端的“葉子路徑”。

示例如下:

用于删除檔案,如果指定路徑是目錄而非檔案的話,就會抛出<code>IsADirectoryError</code>異常。删除目錄應該使用<code>os.rmdir()</code>函數。

同樣的,對應于<code>os.makedirs()</code>,删除路徑操作<code>os.rmdir()</code>也有一個遞歸删除的函數<code>os.removedirs()</code>,該函數會嘗試從最下級目錄開始,逐級删除指定的路徑,幾乎就是一個<code>os.makedirs()</code>的逆過程;一旦遇到非空目錄即停止。

該函數的作用是将檔案或路徑重命名,一般調用格式為<code>os.rename(src, dst)</code>,即将<code>src</code>指向的檔案或路徑重命名為<code>dst</code>指定的名稱。

注意,如果指定的目标路徑在其他目錄下,該函數還可實作檔案或路徑的“剪切并粘貼”功能。但無論直接原地重命名還是“剪切粘貼”,中間路徑都必須要存在,否則就會抛出<code>FileNotFoundError</code>異常。如果目标路徑已存在,Windows 下會抛出<code>FileExistsError</code>異常;Linux 下,如果目标路徑為空且使用者權限允許,則會靜默覆寫原路徑,否則抛出<code>OSError</code>異常,

和上兩個函數一樣,該函數也有對應的遞歸版本<code>os.renames()</code>,能夠建立缺失的中間路徑。

注意,這兩種情況下,如果函數執行成功,都會調用<code>os.removedir()</code>函數來遞歸删除源路徑的最下級目錄。

“getcwd”實際上是“get the current working directory”的簡寫,顧名思義,也就是說這個函數的作用是“擷取目前工作路徑”。在程式運作的過程中,無論實體上程式在實際存儲空間的什麼地方,“目前工作路徑”即可認為是程式所在路徑;與之相關的“相對路徑”、“同目錄下子產品導入”等相關的操作均以“目前工作路徑”為準。

在互動式環境中,傳回的就是互動終端打開的位置;而在 Python 檔案中,傳回的則是檔案所在的位置。

在 Windows 下會有如下輸出:

Linux 下的輸出則是:

“chdir”其實是“change the directory”的簡寫,是以<code>os.chdir()</code>的用處實際上是切換目前工作路徑為指定路徑。其中“指定路徑”需要作為參數傳入函數<code>os.chdir()</code>,該參數既可以是文本或位元組型字元串,也可以是一個檔案描述符,還可以是一個廣義的類路徑(path-like)對象。若指定路徑不存在,則會抛出<code>FileNotFoundError</code>異常。

在 Windows 下,調用該函數的效果為:

在 Linux 下的效果則是:

有了這個函數,跨目錄讀寫檔案和調用子產品就會變得非常友善了,很多時候也就不必再反複将同一個檔案在各個目錄之間複制粘貼運作,腳本完全可以坐鎮中軍,在一個目錄下完成對其他目錄檔案的操作,正所謂“運籌帷幄之中,決勝于千裡之外”也。

舉例來說,可以通過将“目前工作目錄”切換到父目錄,進而直接通路父目錄的檔案内容:

其實這個子產品是<code>os</code>子產品根據系統類型從另一個子產品導入的,并非直接由<code>os</code>子產品實作,比如<code>os.name</code>值為<code>nt</code>,則在<code>os</code>子產品中執行<code>import ntpath as path</code>;如果<code>os.name</code>值為<code>posix</code>,則導入<code>posixpath</code>。

使用該子產品要注意一個很重要的特性:<code>os.path</code>中的函數基本上是純粹的字元串操作。換句話說,傳入該子產品函數的參數甚至不需要是一個有效路徑,該子產品也不會試圖通路這個路徑,而僅僅是按照“路徑”的通用格式對字元串進行處理。

更進一步地說,<code>os.path</code>子產品的功能我們都可以自己使用字元串操作手動實作,該子產品的作用是讓我們在實作相同功能的時候不必考慮具體的系統,尤其是不需要過多關注檔案系統分隔符的問題。

這是一個十分實用的函數,可以将多個傳入路徑組合為一個路徑。實際上是将傳入的幾個字元串用系統的分隔符連接配接起來,組合成一個新的字元串,是以一般的用法是将第一個參數作為父目錄,之後每一個參數即使下一級目錄,進而組合成一個新的符合邏輯的路徑。

但如果傳入路徑中存在一個“絕對路徑”格式的字元串,且這個字元串不是函數的第一個參數,那麼其他在這個參數之前的所有參數都會被丢棄,餘下的參數再進行組合。更準确地說,隻有最後一個“絕對路徑”及其之後的參數才會展現在傳回結果中。

将傳入路徑規範化,傳回一個相應的絕對路徑格式的字元串。

也就是說當傳入路徑符合“絕對路徑”的格式時,該函數僅僅将路徑分隔符替換為适應目前系統的字元,不做其他任何操作,并将結果傳回。所謂“絕對路徑的格式”,其實指的就是一個字母加冒号,之後跟分隔符和字元串序列的格式:

當指定的路徑不符合上述格式時,該函數會自動擷取目前工作路徑,并使用<code>os.path.join()</code>函數将其與傳入的參數組合成為一個新的路徑字元串。示例如下:

該函數傳回傳入路徑的“基名”,即傳入路徑的最下級目錄。

整這個函數要注意的一點是,傳回的“基名”實際上是傳入路徑最後一個分隔符之後的子字元串,也就是說,如果最下級目錄之後還有一個分隔符,得到的就會是一個空字元串:

與上一個函數正好相反,傳回的是最後一個分隔符前的整個字元串:

哈哈實際上前兩個函數都是弟弟,這個函數才是老大。

函數<code>os.path.split()</code>的功能就是将傳入路徑以最後一個分隔符為界,分成兩個字元串,并打包成元組的形式傳回;前兩個函數<code>os.path.dirname()</code>和<code>os.path.basename()</code>的傳回值分别是函數<code>os.path.split()</code>傳回值的第一個、第二個元素。就連二者的具體實作都十分真實:

通過<code>os.path.join()</code>函數又可以把它們組合起來得到原先的路徑。

這個函數用于判斷路徑所指向的位置是否存在。若存在則傳回<code>True</code>,不存在則傳回<code>False</code>:

一般的用法是在需要持久化儲存某些資料的場景,為避免重複建立某個檔案,需要在寫入前用該函數檢測一下相應檔案是否存在,若不存在則建立,若存在則在檔案内容之後增加新的内容。

該函數判斷傳入路徑是否是絕對路徑,若是則傳回<code>True</code>,否則傳回<code>False</code>。當然,僅僅是檢測格式,同樣不對其有效性進行任何核驗:

這兩個函數分别判斷傳入路徑是否是檔案或路徑,注意,此處會核驗路徑的有效性,如果是無效路徑将會持續傳回<code>False</code>。

本文詳細介紹了與作業系統互動的<code>os</code>子產品中一些常用的屬性和函數,基本可以覆寫初階的學習和使用。有了這些功能,我們已經可以寫出一些比較實用的腳本了。

除了文中介紹的函數外,<code>os</code>子產品還有很多更加複雜的功能,但大多是我們暫時用不到的,以後用到會進一步講解。

示例代碼:python-100-days

Python3 文檔-标準庫

Python3 文檔-庫-os

關注公衆号:python技術,回複"python"一起學習交流

第26天:Python 标準庫之 os 子產品詳解

作者:純潔的微笑

出處:www.ityouknow.com

資源:微信搜【純潔的微笑】關注我,回複 【程式員】【面試】【架構師】有我準備的一線程式必備計算機書籍、大廠面試資料和免費電子書。 一共1024G的資料,希望可以幫助大家提升技術和能力。

本文如對您有幫助,還請多幫 【推薦】 下此文。

點我了解:Tooool-程式員一站式導航網站