为什么你应该开始习惯使用 pathlib
幾年前,當我發現 Python 的新 pathlib 模塊時,我最初認為它是 os.path 模塊的一個稍微笨拙和不必要的面向對象版本。我錯了。Python 的 pathlib 模塊實際上很棒!
在本文中,我將嘗試在pathlib上向你推銷。我希望本文將激勵你在任何需要使用 Python 中的文件時使用 Python 的 pathlib 模塊。
os.path 笨拙
os.path 模塊一直是我們用來處理 Python 中的路徑的庫。你需要的東西差不多都包含在內了,但有時它會很顯得笨重。
你應該像這樣導入它?
?
import os.pathBASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) TEMPLATES_DIR = os.path.join(BASE_DIR, 'templates')還是像這樣?
?
from os.path import abspath, dirname, joinBASE_DIR = dirname(dirname(abspath(__file__))) TEMPLATES_DIR = join(BASE_DIR, 'templates')或者,該 join 函數的命名過于籠統,我們還可以這樣做:
?
from os.path import abspath, dirname, join as joinpathBASE_DIR = dirname(dirname(abspath(__file__))) TEMPLATES_DIR = joinpath(BASE_DIR, 'templates')但是,我覺得這些都有點尷尬。我們將字符串傳遞到返回字符串的函數中,然后又將其傳遞給返回字符串的其他函數。這些字符串剛好可以表示路徑,但它們仍然只是字符串。
當多個函數嵌套時,os.path 中字符串進字符串出類的函數非常笨拙,我們需要從內向外來閱讀代碼。如果我們可以把這些嵌套的函數調用轉換成鏈式方法調用,這不是很好嗎?
有了 pathlib 模塊,我們就可以了!
?
from pathlib import PathBASE_DIR = Path(__file__).resolve().parent.parent TEMPLATES_DIR = BASE_DIR.joinpath('templates')os.path 模塊需要函數嵌套,但是 pathlib 模塊的 path 類允許我們鏈式操作 Path 對象上的方法和屬性,以獲得等效的路徑表示。
也許你在想:等等,這些路徑對象不是一回事:它們是對象,不是路徑字符串!不急,我們將稍后來討論這個問題(提示:這些字符串幾乎可以與路徑字符串互換使用)。
os 模塊臃腫
Python 經典模塊 os.path 只用于處理路徑。一旦你真的想通過路徑做一些事情(例如創建一個目錄),你就需要用到另一個 Python 模塊,通常也是 os 下的模塊。
os 模塊有許多用于處理文件和目錄的工具,比如:mkdir、getcwd、chmod、stat、remove、rename 和 rmdir。還有 chdir、link、wald、listdir、makedirs、rename、remvedirs、unlink (與remove相同) 以及 symlink。此外,還有一大堆與文件系統完全無關的東西:fork、getenv、putenv、environ、getlogin 和 system。還有很多在這里沒有羅列的東西。
Python 的 os 模塊什么都能做一點;它有點像是系統相關東西的大雜燴。盡管 os 模塊中有很多不錯的東西,但有時也可能很難找到你要的東西:比如你想在 os模塊中查找與路徑或文件系統相關的內容,則需要進一步挖掘。
pathlib 模塊用 path 對象上的方法替換了許多這些與文件系統相關的 os 功能。
以下代碼創建了src/_pypackages_目錄,并將 .editorconfig 文件重命名為 src/.editorconfig:
?
import os import os.pathos.makedirs(os.path.join('src', '__pypackages__'), exist_ok=True) os.rename('.editorconfig', os.path.join('src', '.editorconfig'))使用 Path 對象執行相同的操作:
?
from pathlib import PathPath('src/__pypackages__').mkdir(parents=True, exist_ok=True) Path('.editorconfig').rename('src/.editorconfig')注意,由于鏈式方法,pathlib 代碼將路徑放在第一位!
正如 Python 之禪所說,“名稱空間是一個很棒的想法,讓我們做更多的事情”。os 模塊是一個非常大的名稱空間,里面有一堆東西。pathlib.path 類是一個比 os 模塊更小、目標更明確的命名空間。此路徑命名空間中的方法返回路徑對象,允許方法鏈式操作而不是字符串拼接式的嵌套函數調用。
別忘了還有 GLOB 模塊!
os 和 os.path 模塊并不是 Python 標準庫中唯一與文件路徑/文件系統相關的功能模塊。glob 模塊是另一個處理路徑相關的模塊。
我們可以使用 glob.glob 函數查找與特定模式匹配的文件:
?
from glob import globtop_level_csv_files = glob('*.csv') all_csv_files = glob('**/*.csv', recursive=True)新的 pathlib 模塊同樣包括類似 glob 的功能。
?
from pathlib import Pathtop_level_csv_files = Path.cwd().glob('*.csv') all_csv_files = Path.cwd().rglob('*.csv')當重度使用 pathlib 之后,你可能會完全忘記 glob 模塊的存在: PATH 對象已經提供了的所有 glob 模塊所具備的功能。
pathlib 讓簡單變得更簡單
pathlib 模塊將許多復雜的情況變得簡單,但它也可以使一些簡單的事情變得更簡單。
需要讀取一個或多個文件中的所有文本?
你可以使用 with 語句塊打開文件、讀取其內容然后關閉文件:
?
from glob import globfile_contents = [] for filename in glob('**/*.py', recursive=True):with open(filename) as python_file:file_contents.append(python_file.read())或者,你可以用 Path 對象的 read_text 方法,在一行代碼中用列表解析功能將文件內容讀取到一個新列表中:
?
from pathlib import Pathfile_contents = [path.read_text()for path in Path.cwd().rglob('*.py') ]如果我需要寫入文件呢?
你可以使用 open 上下文管理器:
?
with open('.editorconfig') as config:config.write('# config goes here')或者使用 write_text 方法:
?
Path('.editorconfig').write_text('# config goes here')如果你更喜歡使用 open (無論是作為上下文管理器還是其他方式),你同樣可以在 PATH 對象上使用 OPEN 方法:
?
from pathlib import Pathpath = Path('.editorconfig') with path.open(mode='wt') as config:config.write('# config goes here')或者,從 Python3.6 開始,你甚至可以將 PATH 對象傳遞給內置的 open 函數:
?
from pathlib import Pathpath = Path('.editorconfig') with open(path, mode='wt') as config:config.write('# config goes here')PATH 對象讓你的代碼更加明確
以下三個變量指向什么?它們的值代表什么?
?
person = '{"name": "Trey Hunner", "location": "San Diego"}' pycon_2019 = "2019-05-01" home_directory = '/home/trey'這些變量中的每一個都指向一個字符串。
這些字符串表示不同的東西:一個是 JSON blob,一個是日期,還有一個是文件路徑。
以下是這些對象更有用的表示:
?
from datetime import date from pathlib import Pathperson = {"name": "Trey Hunner", "location": "San Diego"} pycon_2019 = date(2019, 5, 1) home_directory = Path('/home/trey')JSON 對象可以反序列化到字典,日期在本地使用 datetime.date 對象表示,文件系統路徑現在可以使用 pathlib.path 對象統一表示。
使用 Path 對象可以使代碼更加明確。如果要表示日期,則可以使用 Date 對象。如果試圖表示文件路徑,則可以使用 Path 對象。
我并非面向對象編程的堅定擁護者。類增加了另一層抽象層,而抽象有時會增加更多的復雜性無法保持簡單化。但是 pathlib.Path 類是一個有用的抽象。它也正在迅速成為一個普遍接受的抽象。
感謝 PEP519,文件路徑對象現在成為使用路徑的標準。在 Python3.6 中,內置的 open 函數以及 os、shutil 和 os.path 模塊中的各種函數都可以與 pathlib.path 對象一起正常工作。你可以從現在開始使用 pathlib,而不需要改動大多數使用路徑的代碼!
pathlib 還缺少什么?
雖然 pathlib 是偉大的,但它并不是包羅萬象的。我無意中發現了一些缺失的特性,我希望 pathlib 模塊能夠包括這些特性。
我注意到的第一個缺陷是 pathlib.Path 的方法中缺少與 shutil 等效的功能。
雖然可以將路徑對象(和類似路徑的對象)傳遞給高層的 shutil 函數進行復制/刪除/移動文件和目錄的操作,但是 Path 對象上沒有與此等效的方法。
因此,要復制文件,你仍然需要執行如下操作:
?
from pathlib import Path from shutil import copyfilesource = Path('old_file.txt') destination = Path('new_file.txt') copyfile(source, destination)同樣也沒有與 os.chdir 等效的 pathlib 功能。
這意味著如果需要更改當前工作目錄,仍需要導入 chdir:
?
from pathlib import Path from os import chdirparent = Path('..') chdir(parent)也沒有與 os.walk 函數等價的 pathlib 函數。盡管你可以很容易地使用 pathlib 創建你自己的 walk 式函數。
我希望 pathlib.Path 對象最終可以包含其中一些缺失操作的方法。盡管存在這些缺失的特性,我仍然覺得使用“ pathlib 系”比使用“ os.path 系”更易于管理。
你是否應該始終使用 pathlib?
從Python3.6開始,pathlib.Path 對象幾乎可以在任何已經使用路徑字符串的地方工作。因此,如果你使用的是Python3.6(或更高版本),我認為沒有理由不使用 pathlib。
如果您使用的是 python 3 的早期版本, 則可以將 path 對象始終包裝在 str 調用中, 以便在需要轉義填充字符串的地方獲取相應的字符串返回。雖然有點尷尬, 但還是管用:
?
from os import chdir from pathlib import Pathchdir(Path('/home/trey')) # Python 3.6+ 版 chdir(str(Path('/home/trey'))) # 早期的 Python 3 版不管你使用的是哪個版本的 Python3,我都建議你嘗試一下 pathlib。
什么?你還在用 Python2 ?好吧,萬能的 PyPI 上有個第三方工具 pathlib2 模塊是一個選擇,現在,你可以在任何版本的 Python 上使用 pathlib 啦!。
用 pathlib 讓我的代碼更具可讀性。現在,我處理文件的大多數代碼都默認使用 pathlib,我建議你也這樣做。如果可以用 pathlib,則盡量用吧。
原文:https://treyhunner.com/2018/12/why-you-should-be-using-pathlib/
作者:愛吃魚de大貓
鏈接:https://www.jianshu.com/p/ae194371cf7c
來源:簡書
著作權歸作者所有。商業轉載請聯系作者獲得授權,非商業轉載請注明出處。
總結
以上是生活随笔為你收集整理的为什么你应该开始习惯使用 pathlib的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Roberta-wwm-ext-larg
- 下一篇: Lex-BERT:超越FLAT的中文NE