轉載: https://www.polarxiong.com/archives/Python-os-path-join-產生的斜杠在Windows和Linux下的不同表現和解決方法.html
?
問題描述
我一直以為Python是隔離了操作系統的差異,同樣的function在不同操作系統下會有一致的結果,直到前幾天臨時切換到Windows下發現有些Python代碼跑不出來,才發現如
os.path.join()
這樣的方法在不同操作系統下的表現是不一致的。
例如
Python
import os.path
print(os.path.join('a', 'b', 'c'))
在Linux/macOS下會顯示
a/b/c
而在Windows下會顯示
a\b\c
即
os.path.join()
在Linux/macOS下會以斜杠(
/
)分隔路徑,而在Windows下則會以反斜杠(
\
)分隔路徑
。
這種不一致的表現在遇到jinja2下include模板文件路徑時就會由于jinja2只支持斜杠(
/
),而在Windows下使用
os.path.join()
會出現反斜杠(
\
),而造成找不到模板文件錯誤,參考這個issue。
原因分析
這種內置標準庫方法的不一致從哪來的?官方文檔實際上早就有明顯的暗示了。
在
os.path
的官方文檔頁面11.2. os.path — Common pathname manipulations — Python 3.7.0 documentation開始位置就提到源代碼文件根據不同操作系統在三個不同文件中:
Source code: Lib/posixpath.py (for POSIX), Lib/ntpath.py (for Windows NT), and Lib/macpath.py (for Macintosh)
可見在安裝Python時就會根據不同操作系統,僅使用對應操作系統類別的
os.path
模塊。如果順著源碼去看,就會發現
os.path.join()
在Linux下是以斜杠(
/
)作為分隔符的,而在Windows下則是以反斜杠(
\
)作為分隔符的。
Mac的一些細節
如果跟著看Macintosh操作系統對應的源碼Lib/macpath.py的話,會很驚訝地發現Macintosh下不是以斜杠(
/
)也不是以反斜杠(
\
),而是以冒號(
:
)作為分隔符的,是不是很震驚:我的mac怎么可能是以冒號(
:
)為分隔符的?!
這其實是一個歷史問題了,這里Lib/macpath.py僅應用到了2001發布的Mac OS X之前的Macintosh操作系統中,那時的Macintosh確實是用冒號(
:
)為分隔符的。而從2001年的Mac OS X開始,到2012年的OS X,再到2016年的macOS,都采用了遵循Unix的斜杠(
/
)分隔符,也就直接使用Linux的源碼Lib/posixpath.py了。
為什么Windows要使用反斜杠(
\
)
為什么Windows不使用斜杠(
/
),而獨樹一幟使用反斜杠(
\
)呢,專門為了為難程序員?
這其實也是個歷史問題,歸根到底還是因為Windows為了保持對DOS的兼容性,而DOS為什么要使用反斜杠(
\
)就說來話長了,可以參考MSDN上的一篇博文:Why is the DOS path character ""? – Larry Osterman's WebLog。
解決方法
從上面的分析可以發現
os.path.join()
僅包含對應操作系統類型的實現,所以我們無法通過指定參數的形式生成諸如適用于Linux或Windows的路徑,那么如何解決這一問題呢?這里以在Windows下生成Linux格式(斜杠(
/
)分隔符)路徑為例來說明。
通過
str.replace()
這是一種簡單直接的方法,直接把Windows下
os.path.join()
生成的反斜杠(
\
)全部替換為斜杠(
/
),如:
Python
import os.path
result = os.path.join('a', 'b', 'c')
print(result)
result = result.replace('\\', '/')
print(result)
會得到
a\b\c
a/b/c
通過
pathlib.PurePath.as_posix()
從Python 3.4開始可以通過
pathlib.PurePath.as_posix()
來生成斜杠(
/
)格式的路徑,其實其實現原理和
str.replace()
并沒有太大區別。例如:
Python
import os.path
from pathlib import Path
result = os.path.join('a', 'b', 'c')
print(result)
result = Path(result).as_posix()
print(result)
會得到
a\b\c
a/b/c
參考
- 11.2. os.path — Common pathname manipulations — Python 3.7.0 documentation
- 11.1. pathlib — Object-oriented filesystem paths — Python 3.7.0 documentation
更多文章、技術交流、商務合作、聯系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號聯系: 360901061
您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元
