Java 的 Class 提供有一個 getResource(name) 方法,可以用相對某 .class 檔的位置來解讀 name 所表示的相對路徑。
在 Python 裡也有類似的需求,為了程式的可攜性,需要以相對於 .py 檔的方式來描述某個外部檔的位置。假設下面的目錄結構:
/tmp$ tree a
a/
|-- a.txt <-- 內容為 "content of a.txt"
`-- b/
|-- c/
|-- mod.py
`-- othermod.py
2 directories, 2 files
/tmp/a/b/mod.py 會將 /tmp/a.txt 的內容印容印出。它的內容如下:
import os from os.path import dirname, abspath, join # 取得 mod.py 所在的路徑 (相對於 current working directory) mod_dir = dirname(__file__) # 不直接寫成 '../a.txt' 是為了不要跟 OS 相依 a_pathname = abspath(join(mod_dir, '..', 'a.txt')) print 'CWD:', os.getcwd() print open(a_pathname, 'r').read()
不論從哪個位置執行 mod.py (會導致 current working directory 起變化),都能正常地印出 /tmp/a/a.txt 的內容:
/tmp$ python a/b/mod.py CWD: /tmp content of a.txt /tmp$ cd a/b/c /tmp/a/b/c$ python ../mod.py CWD: /tmp/a/b/c content of a.txt
當然也可以藉由其他 module 來定位:
import os, othermod from os.path import dirname, abspath, join mod_dir = dirname(othermod.__file__) # 取得 othermod.py 所在的路徑 a_pathname = abspath(join(mod_dir, '..', 'a.txt')) print 'CWD:', os.getcwd() print open(a_pathname, 'r').read()
根據上面的實驗結果,我們可以寫一個 abspath(relpath, mod) 來模擬 Java 中 Class.getResource(name) 的行為,也可以做為 os.path.abspath(path) 的擴充。
import os
def abspath(relpath, mod):
# 呼叫端不用擔心不同 OS 的分隔字元
relpath = relpath.replace('/', os.sep).replace('\\', os.sep)
if mod is None: return os.path.abspath(relpath)
base_dir = os.path.dirname(mod.__file__)
pathname = os.path.join(base_dir, relpath)
return os.path.abspath(pathname)
|
Tip
|
可以用 sys.modules[__name__] 來取得 current module. |
這裡提到的技巧,也很適合用在執行期動態配置 sys.path 。
參考資料: