攝影或3C

Python `os.environ[“PATH”]`(設定 *.exe 路徑)vs `sys.path`(設定 *.py 路徑)教學:用 Whisper 與 ffmpeg 看懂兩種很像的 path

這篇教學要講的是一個很常混在一起的觀念:

– `os.environ[“PATH”]`

– `sys.path.append(…)`

很多人第一次看到這兩個,都會覺得:

– 反正都是 path

– 反正都是在「讓程式找得到東西」

– 看起來只差一個是 `os.environ`,一個是 `sys.path`

但它們其實不在同一層。

最簡單的一句話是:

– `os.environ[“PATH”]`:讓作業系統找「可執行檔」

– `sys.path`:讓 Python 找「可 import 的東西」,
白話講通常就是 `.py` 檔,
或一個可被當成模組資料夾的目錄
(最常見是裡面有 `__init__.py`)

## 先用 Whisper + ffmpeg 這個例子理解

這個例子很適合,因為它剛好同時碰到兩層:

1. `whisper` 本身是一個 Python 模組

2. `ffmpeg.exe` 是一個外部可執行檔

所以你可能會遇到兩種完全不同的錯誤。

### 情況 A:Python 找不到 `whisper`

例如:

“`python

import whisper

“`

結果報:

“`text

ModuleNotFoundError: No module named ‘whisper’

“`

這代表:

– Python 解譯器找不到 `whisper` 這個模組

– 這通常是 interpreter、虛擬環境、site-packages、`sys.path` 這一層的問題

### 情況 B:`whisper` 可以 import,但跑起來找不到 `ffmpeg.exe`

例如 `whisper` 已經能 import,

但執行轉音訊時,底層 subprocess 找不到 `ffmpeg`。

這時問題通常不是 `sys.path`,而是:

– 作業系統找不到 `ffmpeg.exe`

– 也就是「作業系統搜尋可執行檔的路徑(PATH)」這一層有問題

所以同樣都是「找不到」,

但其實是兩種完全不同的找法。

## `os.environ[“PATH”]` 在做什麼

`os.environ[“PATH”]` 對應的是作業系統層的搜尋路徑。

當你在終端機輸入:

“`text

python

pip

git

ffmpeg

“`

系統會去 `os.environ[“PATH”]` 裡列出的資料夾,
一個一個找對應的執行檔。

所以它主要解決的是:

– `ffmpeg.exe` 找不找得到

– `python.exe` 找不找得到

– `pip.exe` 找不找得到

例如:

“`python

import os

print(os.environ[“PATH”])

“`

你看到的通常會是一大串資料夾路徑。

### 臨時把 `ffmpeg\bin` 加進 PATH

“`python

import os

ffmpeg_bin_path = r”C:\ffmpeg\bin”

os.environ[“PATH”] = ffmpeg_bin_path + os.pathsep + os.environ[“PATH”]

“`

注意:這裡加進 `os.environ[“PATH”]` 的是
`C:\ffmpeg\bin` 這個資料夾,
不是 `C:\ffmpeg\bin\ffmpeg.exe` 這個檔案本身。

這裡特別把 `ffmpeg_bin_path` 放在前面,
不是單純寫法習慣,
而是為了讓這個目錄裡的 `ffmpeg.exe` 取得更高優先權。

也就是說,系統之後找 `ffmpeg.exe` 時,會先找:

– `C:\ffmpeg\bin`

– 再找原本 `os.environ[“PATH”]` 裡既有的那些目錄

這在電腦上同時存在多個版本的
`ffmpeg.exe`、`dot.exe`、`python.exe` 時很有用。

如果你改寫成下面這種:

“`python

os.environ[“PATH”] += os.pathsep + ffmpeg_bin_path

“`

那就會變成把新路徑加到最後面。

這種寫法不是不能用,而是優先權比較低:

– 前面原本 PATH 裡如果已經有另一個 `ffmpeg.exe`

– 系統通常會先找到舊的那個

– 你剛加進去的版本反而不一定會被用到

所以:

– 把新路徑放前面:表示「先用我指定的這個版本」

– 把新路徑加到後面:表示「前面都找不到時再用我」

這樣做的效果是:

– 只在目前這個 Python 程序中暫時生效

– 讓這個程序之後啟動的子程序,
也能比較容易找到 `ffmpeg.exe`

這裡刻意用:

“`python

os.pathsep

“`

而不是直接硬寫 `;`。

因為:

– Windows 的 path 分隔符是 `;`

– Linux / macOS 是 `:`

所以 `os.pathsep` 比較穩。

## `sys.path.append(…)` 在做什麼

`sys.path` 是 Python 解譯器用來找模組的路徑清單。

當你寫:

“`python

import my_utils

“`

Python 不看 `os.environ[“PATH”]`,它看的是:

“`python

import sys

print(sys.path)

“`

也就是:

– 目前工作目錄

– 標準函式庫

– site-packages

– 你手動 append 的資料夾

所以它主要解決的是:

– `import whisper` 找不找得到

– `import my_utils` 找不找得到

– `import project.helpers` 找不找得到

### 臨時把自訂模組目錄加進 `sys.path`

“`python

import sys

sys.path.append(r”D:\user\Python\my_project\src”)

“`

這樣做的效果是:

– 只在目前這個 Python 程序中暫時生效

– 讓 Python 之後可以從這個目錄 import 模組

## 兩者最核心的差別

如果只用一句話區分:

– `os.environ[“PATH”]` 找的是 executable

– `sys.path` 找的是 Python module

你也可以用下面這個對照表記住。

## 為什麼這兩個看起來很像

因為它們有三個共同點:

1. 都是一串路徑

2. 都是在「找東西」

3. 都可以在程式執行時暫時修改

所以很容易被誤認成同一件事。

但它們的搜尋對象不同:

– `os.environ[“PATH”]` 是給系統找程式

– `sys.path` 是給 Python 找模組

## `No module named …` 一般優先看什麼

如果錯誤是:

“`text

ModuleNotFoundError: No module named ‘xxx’

“`

一般優先檢查這些:

1. VS Code / Notebook 選到的 interpreter 是否正確

2. 套件是否真的安裝在那個 interpreter 對應的環境

3. 專案結構是否正確

4. 啟動方式是否合理,例如要不要用 `python -m package.module`

5. 是否只是編輯器分析錯誤,需要 `python.analysis.extraPaths`

不是先去改 `os.environ[“PATH”]`。

## `ffmpeg not found` 一般優先看什麼

如果是 `whisper` 類似工具能 import,

但執行時找不到 `ffmpeg`,那優先看的是:

1. `ffmpeg.exe` 是否真的存在

2. 它的 `bin` 目錄是否在系統 PATH 裡,也就是目前程序看到的 `os.environ[“PATH”]` 裡

3. 目前 Python 程式是否有把 `ffmpeg_bin_path` 臨時加進 `os.environ[“PATH”]`

這時通常不是 `sys.path` 的問題。

## 除了 `ffmpeg.exe`,還有哪些常見的 PATH 類外部工具?

如果 Python 套件本身可以 import,

但執行時還要再呼叫外部工具,
那常常就是 `os.environ[“PATH”]` / 系統 PATH 這一層。

比較常見、也很適合拿來理解的例子有:

– `ffmpeg.exe`

– `graphviz.exe`(很多時候實際缺的是 `dot.exe`)

– `dot.exe`

– `tesseract.exe`

– `pandoc.exe`

– `git.exe`

其中前面幾個最典型:

– `ffmpeg.exe`:影音轉檔、Whisper、moviepy、pydub

– `graphviz.exe` / `dot.exe`:流程圖、依賴圖、Graphviz 輸出

– `tesseract.exe`:OCR,常見於 `pytesseract`

### PaddleOCR 算不算這一類?

通常不算典型的 `os.environ[“PATH”]` 類外部 exe 依賴。

因為 PaddleOCR 比較常見的依賴是:

– `paddleocr`

– `paddlepaddle`

– GPU / CUDA / cuDNN

– DLL 或底層 runtime

– 模型檔

也就是說,PaddleOCR 比較常見的是 Python 套件與 runtime 依賴,

不是像 `tesseract.exe` 那樣,先去系統 PATH 裡找一個外部執行檔。

## `sys.path.append(…)` 能不能用

可以,但通常是臨時補丁,不是最漂亮的正式解法。

它適合:

– notebook

– 快速測試

– 一次性腳本

– 臨時驗證模組路徑

不太適合:

– 長期正式專案

– 多人協作

– 結構已固定的 package 專案

因為它會讓 import 規則散落在程式內部。

## `os.environ[“PATH”]` 能不能在程式內改

可以,但同樣屬於程序內暫時修補。

例如:

“`python

import os

ffmpeg_bin_path = r”C:\ffmpeg\bin”

os.environ[“PATH”] = ffmpeg_bin_path + os.pathsep + os.environ[“PATH”]

“`

這種做法很適合:

– 單一腳本

– notebook

– 臨時測試

– 你知道某個外部工具只差最後一步路徑沒接上

但如果是正式環境,通常更建議:

– 直接把 `ffmpeg\bin` 加到系統 PATH

– 讓所有終端機 / 工具都能共用

## 這個例子裡的三層關係

拿 `whisper` 當例子,可以把整件事拆成三層:

### 第 1 層:VS Code / Notebook 選哪個 Python

這一層常和:

– `python.defaultInterpreterPath`

– 實際選到的 interpreter

有關。

如果這裡就選錯了,後面很多事情都會錯。

### 第 2 層:Python 能不能 import 模組

這一層常和:

– site-packages

– `sys.path`

– 專案結構

有關。

例如:

– `import whisper`

– `import my_utils`

### 第 3 層:被呼叫的外部工具能不能被系統找到

這一層常和:

– `os.environ[“PATH”]`

– 系統環境變數 PATH

有關。

例如:

– `ffmpeg.exe`

– `git.exe`

– `pandoc.exe`

## 最實用的一句判斷

如果你看到的是:

“`text

No module named …

“`

先想:

– 這是 Python 找模組失敗

– 優先看 interpreter、環境、`sys.path`

如果你看到的是:

“`text

ffmpeg not found

“`

先想:

– 這是系統找可執行檔失敗

– 優先看 `os.environ[“PATH”]` / 系統 PATH

## 最後一句話

`os.environ[“PATH”]` 和 `sys.path` 看起來都像「路徑清單」,

但它們分別服務兩個不同世界:

– `os.environ[“PATH”]` 是作業系統的世界

– `sys.path` 是 Python import 的世界

用 `whisper` 與 `ffmpeg` 這個例子去記,通常最不容易搞混:

– `whisper` 是 module,所以偏 `sys.path`

– `ffmpeg.exe` 是 executable,所以偏 `os.environ[“PATH”]`

推薦hahow線上學習python: https://igrape.net/30afN

儲蓄保險王

儲蓄險是板主最喜愛的儲蓄工具,最喜愛的投資理財工具則是ETF,最喜愛的省錢工具則是信用卡