<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          求求你,別用 os.path 了!

          共 9569字,需瀏覽 20分鐘

           ·

          2021-05-16 14:10

          作者:somenzz

          來源:Python七號

          前段時間,在使用新版本的 Django 時,我發(fā)現(xiàn)了 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

          于是我就好奇,os 和 pathlib 同樣是標準庫,為什么 pathlib 得到了 Django 的青睞?學習了一番 pathlib 之后,發(fā)現(xiàn)這是一個非常高效便捷的工具,用它來處理文件系統(tǒng)路徑相關的操作最合適不過,集成了很多快捷的功能,提升你的編程效率,那是妥妥的。

          接下來讓一起看一下,為什么 pathlib 更值得我們使用。

          pathlib vs os

          話不多說,先看下使用對比:比如說

          1. 打印當前的路徑:

          使用 os:

          In [13]: import os

          In [14]: os.getcwd()
          Out[14]: '/Users/aaron'

          使用 pathlib:

          In [15]: from pathlib import Path

          In [16]: Path.cwd()
          Out[16]: PosixPath('/Users/aaron')
          In [17]: print(Path.cwd())
          /Users/aaron

          使用 print 打印的結(jié)果是一樣的,但 os.getcwd() 返回的是字符串,而 Path.cwd() 返回的是 PosixPath 類,你還可以對此路徑進行后續(xù)的操作,會很方便。

          1. 判斷路徑是否存在:

          使用 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 更易讀,更面向?qū)ο蟆?/p>

          1. 顯示文件夾的內(nèi)容
          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 返回的是一個生成器,這在目錄內(nèi)文件特別多的時候可以大大節(jié)省內(nèi)存,提升效率。

          1. 通配符支持

          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')]
          1. 便捷的讀寫文件操作

          這是 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()
          ...
          '#!/usr/bin/env python3\n'
          1. 獲取文件的元數(shù)據(jù)
          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]: True

          In [62]: p.is_dir()
          Out[62]: False

          In [63]: p.is_file()
          Out[63]: True

          In [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'

          1. 路徑的連接 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')
          1. 路徑匹配
          >>> PurePath('a/b.py').match('*.py')
          True
          >>> PurePath('/a/b/c.py').match('b/*.py')
          True
          >>> PurePath('/a/b/c.py').match('a/*.py')
          False

          pathlib 出現(xiàn)的背景和要解決的問題

          pathlib 目的是提供一個簡單的類層次結(jié)構(gòu)來處理文件系統(tǒng)的路徑,同時提供路徑相關的常見操作。那為什么不使用 os 模塊或者 os.path 來實現(xiàn)呢?

          許多人更喜歡使用 datetime 模塊提供的高級對象來處理日期和時間,而不是使用數(shù)字時間戳和 time 模塊 API。同樣的原因,假如使用專用類表示文件系統(tǒng)路徑,也會更受歡迎。

          換句話說,os.path 是面向過程風格的,而 pathlib 是面向?qū)ο箫L格的。Python 也在一直在慢慢地從復制 C 語言的 API 轉(zhuǎn)變?yōu)閲@各種常見功能提供更好,更有用的抽象。

          其他方面,使用專用的類處理特定的需求也是很有必要的,例如 Windows 路徑不區(qū)分大小寫。

          在這樣的背景下,pathlib 在 Python 3.4 版本加入標準庫。

          pathlib 的優(yōu)勢和劣勢分別是什么

          pathlib 的優(yōu)勢在于考慮了 Windows 路徑的特殊性,同時提供了帶 I/O 操作的和不帶 I/O 操作的類,使用場景更加明確,API 調(diào)用更加易懂。

          先看下 pathlib 對類的劃分:

          圖中的箭頭表示繼承自,比如 Path 繼承自 PurePath,PurePath 表示純路徑類,只提供路徑常見的操作,但不包括實際 I/O 操作,相對安全;Path 包含 PurePath 的全部功能,包括 I/O 操作。

          PurePath 有兩個子類,一個是 PureWindowsPath,表示 Windows 下的路徑,不區(qū)分大小寫,另一個是 PurePosixPath,表示其他系統(tǒng)的路徑。有了 PureWindowsPath,你可以這樣對路徑進行比較:

          from pathlib import PureWindowsPath
          >>> PureWindowsPath('a') == PureWindowsPath('A')
          True

          PurePath 可以在任何操作系統(tǒng)上實例化,也就是說與平臺無關,你可以在 unix 系統(tǒng)上使用 PureWindowsPath,也可以在 Windows 系統(tǒng)上使用 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

          可以看出,同一個類可以相互比較,不同的類比較的結(jié)果是 False。

          相反,包含 I/O 操作的類 PosixPath 及 WindowsPath 只能在對應的平臺實例化:

          In [8]: from pathlib import PosixPath,WindowsPath

          In [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 system

          In [11]:

          要說劣勢,如果有的話,那就是在選擇類時會比較困惑,到底用哪一個呢?其實如果你不太確定的話,用 Path 就可以了,這也是它的名稱最短的原因,因為更加常用,短點的名稱編寫的更快。

          適用的場景

          如果要處理文件系統(tǒng)相關的操作,選 pathlib 就對了。

          一些關鍵點

          獲取家目錄:

          In [70]: from pathlib import Path

          In [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 風格轉(zhuǎn) 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')

          是不是非常方便?

          技術(shù)的底層原理和關鍵實現(xiàn)

          pathlib 并不是基于 str 的實現(xiàn),而是基于 object 設計的,這樣就嚴格地區(qū)分了 Path 對象和字符串對象,同時也用到了一點 os 的功能,比如 os.name,os.getcwd 等,這一點大家可以看 pathlib 的源碼了解更多。

          最后的話

          本文分享了 pathlib 的用法,后面要處理路徑相關的操作時,你應該第一時間想到 pathlib,不會用沒有關系,搜索引擎所搜索 pathlib 就可以看到具體的使用方法。

          雖然 pathlib 比 os 庫更高級,更方便并且提供了很多便捷的功能,但是我們?nèi)匀恍枰廊绾问褂?os 庫,因為 os 庫是 Python 中功能最強大且最基本的庫之一,但是,在需要一些文件系統(tǒng)操作時,強烈建議使用 pathlib。

          Python貓技術(shù)交流群開放啦!群里既有國內(nèi)一二線大廠在職員工,也有國內(nèi)外高校在讀學生,既有十多年碼齡的編程老鳥,也有中小學剛剛?cè)腴T的新人,學習氛圍良好!想入群的同學,請在公號內(nèi)回復『交流群』,獲取貓哥的微信(謝絕廣告黨,非誠勿擾!)~


          還不過癮?試試它們




          如何用 Python 實現(xiàn)優(yōu)先級調(diào)度器?

          Python 面向切面編程 AOP 和裝飾器

          非常適合小白的 Asyncio 教程

          四個月技術(shù)寫作,我寫了些什么?

          為什么 Python 不用聲明類型?

          Python 之父為什么嫌棄 lambda 匿名函數(shù)?


          如果你覺得本文有幫助
          請慷慨分享點贊,感謝啦
          瀏覽 50
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  成人天天在线 | 色五月欧美 | 婷婷香蕉| 亚洲无码成人在线 | 日韩黄色在线视频 |