dan-carlson-141263

Background

在 Python 中 append sys path 是常用到的東西. 畢竟你可能自己寫了一堆 Code 但又不想全部丟在同一個資料夾底下, 跟一些 config 設定檔的位置. 這些都會需要用到 append path的功能. 但如果用 relative path (相對路徑) 的話又會有一些問題:

  • 只要 current working directory (CWD)在執行期一經變動(os.chdir(), 相對路徑就無法被解讀成正確的位置.
  • 其他 module 也可能用相同的方式將同一個路徑加到 search path 裡, 最後 search path 裡就會有一堆重複的路徑.

以下是我自己個人習慣的開發目錄架構

.
├── README.md
├── config
│   ├── __init__.py
│   └── database.py
├── docs
├── src
│   ├── run.py
└── tests

主要程式都放在 src 這個資料夾裡面. 所以我通常會 appned src 的父目錄. 所以我們的目的就很單純. 不管你現在在那個路徑下執行 src 中的程式都可以順利的 appned src 的父目錄

file

先介紹一下 __file__, __file__ 的值其實就是在命令列上 invoke Python 時給的 script 名稱:

$ python test.py          # 此時 __file__ 是 test.py
$ python ../test.py       # 此時 __file__ 是 ../test.py
$ python hello/../test.py # 此時 __file__ 是 hello/../test.py

os.path.dirname & os.path.abspath

首先先看以下的例子:

import os
    
print (__file__)
print (os.path.dirname(__file__))
print (os.path.abspath(__file__))
print (os.path.abspath(os.path.dirname(__file__)))
print (os.path.dirname(os.path.abspath(__file__)))

結果如下:

test.py

/home/paul/test.py
/home/paul
/home/paul

所以我們最後的解法就如下列的程式

run.py

import sys
import os
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))

from config import database as db

接下來你就可以順利的使用 config 裡面的程式碼了. 再也不用擔心 CWD 改變的問題.

Reference