python中os.path和pathlib
前段時間,在使用新版本的 Django 時,我發現了 settings.py 的第一行代碼從
import os BASE_DIR = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))變成了
from pathlib import Path BASE_DIR = Path(__file__).resolve().parent.parent為什么 pathlib 更值得我們使用?
打印當前的路徑
使用 os:
In [13]: import osIn [14]: os.getcwd() Out[14]: '/Users/aaron'使用 pathlib:
In [15]: from pathlib import PathIn [16]: Path.cwd() Out[16]: PosixPath('/Users/aaron') In [17]: print(Path.cwd()) /Users/aaron使用print打印的結果是一樣的,但os.getcwd()返回的是字符串,而 Path.cwd() 返回的是PosixPath類,你還可以對此路徑進行后續的操作,會很方便。
判斷路徑是否存在
使用 os:
In [18]: os.path.exists("/Users/aaron/tmp") Out[18]: True使用 pathlib:
In [21]: tmp = Path("/Users/aaron/tmp")In [22]: tmp.exists() Out[22]: True可以看出pathlib更易讀,更面向對象。
遍歷文件夾
In [38]: os.listdir("/Users/aaron/tmp") Out[38]: ['.DS_Store', '.hypothesis', 'b.txt', 'a.txt', 'c.py', '.ipynb_checkpoints']In [39]: tmp.iterdir() Out[39]: <generator object Path.iterdir at 0x7fa3f20d95f0>In [40]: list(tmp.iterdir()) Out[40]: [PosixPath('/Users/aaron/tmp/.DS_Store'),PosixPath('/Users/aaron/tmp/.hypothesis'),PosixPath('/Users/aaron/tmp/b.txt'),PosixPath('/Users/aaron/tmp/a.txt'),PosixPath('/Users/aaron/tmp/c.py'),PosixPath('/Users/aaron/tmp/.ipynb_checkpoints')]可以看出Path().iterdir返回的是一個生成器,這在目錄內文件特別多的時候可以大大節省內存,提升效率。
通配符支持
os 不支持含有通配符的路徑,但 pathlib 可以:
In [45]: list(Path("/Users/aaron/tmp").glob("*.txt")) Out[45]: [PosixPath('/Users/aaron/tmp/b.txt'), PosixPath('/Users/aaron/tmp/a.txt')]便捷的讀寫文件操作
這是 pathlib 特有的:
f = Path('test_dir/test.txt')) f.write_text('This is a sentence.') f.read_text()也可以使用 with 語句:
p = Path('setup.py')with p.open() as f: f.readline()獲取文件的元數據
In [56]: p = Path("/Users/aaron/tmp/c.py")In [57]: p.stat() Out[57]: os.stat_result(st_mode=33188, st_ino=35768389, st_dev=16777221, st_nlink=1, st_uid=501, st_gid=20, st_size=20, st_atime=1620633580, st_mtime=1620633578, st_ctime=1620633578)In [58]: p.parts Out[58]: ('/', 'Users', 'aaron', 'tmp', 'c.py')In [59]: p.parent Out[59]: PosixPath('/Users/aaron/tmp')In [60]: p.resolve() Out[60]: PosixPath('/Users/aaron/tmp/c.py')In [61]: p.exists() Out[61]: TrueIn [62]: p.is_dir() Out[62]: FalseIn [63]: p.is_file() Out[63]: TrueIn [64]: p.owner() Out[64]: 'aaron'In [65]: p.group() Out[65]: 'staff'In [66]: p.name Out[66]: 'c.py'In [67]: p.suffix Out[67]: '.py'In [68]: p.suffixes Out[68]: ['.py']In [69]: p.stem Out[69]: 'c'路徑的連接 join
相比 os.path.join,使用一個 / 是不是更為直觀和便捷?
>>> p = PurePosixPath('foo') >>> p / 'bar' PurePosixPath('foo/bar') >>> p / PurePosixPath('bar') PurePosixPath('foo/bar') >>> 'bar' / p PurePosixPath('bar/foo')當然,也可以使用 joinpath 方法
>>> PurePosixPath('/etc').joinpath('passwd') PurePosixPath('/etc/passwd') >>> PurePosixPath('/etc').joinpath(PurePosixPath('passwd')) PurePosixPath('/etc/passwd') >>> PurePosixPath('/etc').joinpath('init.d', 'apache2') PurePosixPath('/etc/init.d/apache2') >>> PureWindowsPath('c:').joinpath('/Program Files') PureWindowsPath('c:/Program Files')路徑匹配
>>> PurePath('a/b.py').match('*.py') True >>> PurePath('/a/b/c.py').match('b/*.py') True >>> PurePath('/a/b/c.py').match('a/*.py') Falsepathlib 出現的背景和要解決的問題
pathlib 目的是提供一個簡單的類層次結構來處理文件系統的路徑,同時提供路徑相關的常見操作。那為什么不使用 os 模塊或者 os.path 來實現呢?
許多人更喜歡使用 datetime 模塊提供的高級對象來處理日期和時間,而不是使用數字時間戳和 time 模塊 API。同樣的原因,假如使用專用類表示文件系統路徑,也會更受歡迎。
換句話說,os.path 是面向過程風格的,而 pathlib 是面向對象風格的。Python 也在一直在慢慢地從復制 C 語言的 API 轉變為圍繞各種常見功能提供更好,更有用的抽象。
其他方面,使用專用的類處理特定的需求也是很有必要的,例如 Windows 路徑不區分大小寫。
在這樣的背景下,pathlib 在 Python 3.4 版本加入標準庫。
pathlib 的優勢和劣勢分別是什么
pathlib 的優勢在于考慮了 Windows 路徑的特殊性,同時提供了帶 I/O 操作的和不帶 I/O 操作的類,使用場景更加明確,API 調用更加易懂。
先看下 pathlib 對類的劃分:
圖中的箭頭表示繼承自,比如 Path 繼承自 PurePath,PurePath 表示純路徑類,只提供路徑常見的操作,但不包括實際 I/O 操作,相對安全;Path 包含 PurePath 的全部功能,包括 I/O 操作。
PurePath 有兩個子類,一個是 PureWindowsPath,表示 Windows 下的路徑,不區分大小寫,另一個是 PurePosixPath,表示其他系統的路徑。有了 PureWindowsPath,你可以這樣對路徑進行比較:
from pathlib import PureWindowsPath >>> PureWindowsPath('a') == PureWindowsPath('A') TruePurePath 可以在任何操作系統上實例化,也就是說與平臺無關,你可以在 unix 系統上使用 PureWindowsPath,也可以在 Windows 系統上使用 PurePosixPath,他們還可以相互比較。
>>> from pathlib import PurePosixPath, PureWindowsPath, PosixPath >>> PurePosixPath('a') == PurePosixPath('b') False >>> PurePosixPath('a') < PurePosixPath('b') True >>> PurePosixPath('a') == PosixPath('a') True >>> PurePosixPath('a') == PureWindowsPath('a') False可以看出,同一個類可以相互比較,不同的類比較的結果是 False。
相反,包含 I/O 操作的類 PosixPath 及 WindowsPath 只能在對應的平臺實例化:
In [8]: from pathlib import PosixPath,WindowsPathIn [9]: PosixPath('a') Out[9]: PosixPath('a')In [10]: WindowsPath('a') --------------------------------------------------------------------------- NotImplementedError Traceback (most recent call last) <ipython-input-10-cc7a0d86d4ed> in <module> ----> 1 WindowsPath('a')/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/pathlib.py in __new__(cls, *args, **kwargs)1038 self = cls._from_parts(args, init=False)1039 if not self._flavour.is_supported: -> 1040 raise NotImplementedError("cannot instantiate %r on your system"1041 % (cls.__name__,))1042 self._init()NotImplementedError: cannot instantiate 'WindowsPath' on your systemIn [11]:要說劣勢,如果有的話,那就是在選擇類時會比較困惑,到底用哪一個呢?其實如果你不太確定的話,用 Path 就可以了,這也是它的名稱最短的原因,因為更加常用,短點的名稱編寫的更快。
適用的場景
如果要處理文件系統相關的操作,選 pathlib 就對了。
一些關鍵點
獲取家目錄:
In [70]: from pathlib import PathIn [71]: Path.home() Out[71]: PosixPath('/Users/aaron')父目錄的層級獲取:
>>> p = PureWindowsPath('c:/foo/bar/setup.py') >>> p.parents[0] PureWindowsPath('c:/foo/bar') >>> p.parents[1] PureWindowsPath('c:/foo') >>> p.parents[2] PureWindowsPath('c:/')獲取多個文件后綴:
>>> PurePosixPath('my/library.tar.gar').suffixes ['.tar', '.gar'] >>> PurePosixPath('my/library.tar.gz').suffixes ['.tar', '.gz'] >>> PurePosixPath('my/library').suffixes []Windows 風格轉 Posix:
>>> p = PureWindowsPath('c:\\windows') >>> str(p) 'c:\\windows' >>> p.as_posix() 'c:/windows'獲取文件的 uri:
>>> p = PurePosixPath('/etc/passwd') >>> p.as_uri() 'file:///etc/passwd' >>> p = PureWindowsPath('c:/Windows') >>> p.as_uri() 'file:///c:/Windows'判斷是否絕對路徑:
>>> PurePosixPath('/a/b').is_absolute() True >>> PurePosixPath('a/b').is_absolute() False>>> PureWindowsPath('c:/a/b').is_absolute() True >>> PureWindowsPath('/a/b').is_absolute() False >>> PureWindowsPath('c:').is_absolute() False >>> PureWindowsPath('//some/share').is_absolute() True替換目錄最后一個部分并返回一個新的路徑:
>>> p = PureWindowsPath('c:/Downloads/pathlib.tar.gz') >>> p.with_name('setup.py') PureWindowsPath('c:/Downloads/setup.py')總結
以上是生活随笔為你收集整理的python中os.path和pathlib的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 再也不怕平板泡水了平板泡水开不了机
- 下一篇: 海马属于鱼类吗(海马是否属于鱼类)