Re: [問題] 請問為何os.getcwd()不總在sys.path內?
原諒我只回關於import的部份XD。這部份我發現第一次遇到很難搞懂又常常忘記,我自己
也是邊查邊寫。
import 的邏輯是什麼!?
======================
這邊比較能夠細讀的官方文件是PEP-328和
https://docs.python.org/3/tutorial/modules.html 。
## Absolute Import
Absolute import 非常簡單,只要不是以點(dot)開頭的就是absolute import,例如:
import foo
import foo.bar as bar
from foo import bar
Absolute import的邏輯就是先找built-in module,沒有的話從`sys.path`的資料夾底下
找一個<name>.py的檔案或是<name>的package(package的定義:帶有`__init__.py`)。
`sys.path`的組成包含
* 程式進入的script的資料夾
* `PYTHONPATH`環境變數
* 安裝python時指定的位置,通常是放安裝的檔案
## Relative Import
Relative import 以點作為起始,兩個點代表上一層,以此類推,而且永遠都是用
`from <> import <>` 來敘述。
至於這個"relative"是相對什麼?這個是用當前module的`__name__`來決定
* 如果它是`foo.bar`之類的值,那就是從`foo.bar`來做相對移動。
`foo`就是最上層的module。
* 如果它是`__main__`(當你執行python script的進入點),
那這個script就是最上層的module。
最後,不管是那一種relative import,都不能超過最上層的module。
## Import, the Pythonic Way
首先是,不要使用`from foo import *`這種形式。python的名字是會被覆蓋的,也就是
說如果連續兩行 `from <name> import *`然後又有重複的名字,那就會被第二行覆蓋。
然後,分開程式進入點的檔案(`__name__`是`__main__`)還有package。理由是你的進
入點會變成是`__main__`,那就沒辦法用relative import,那你就只能仰賴`sys.path`
來找你自己開發的檔案。如果你不想要自己加工`sys.path`,那就要把你的package放在
程式進入點那層,也就是這樣
project/
main.py
setup.py
packageA/
...
tests/
funtionA/
test_XXX.py
...
...
最後,盡量不要加工`sys.path`。原因跟第一點一樣是名稱衝突的問題:module是依序在
`sys.path`裡面找,加工會影響其他module,可能會讓後來的module import到錯的檔案,
這種超級難debug。
## Take Away
* absolute import: 用`sys.path`決定
* relative import: 用`__name__`決定,不能超過top-level module
* 不要用`*`、分開entrypoint和package、不要加工`sys.path`
--
※ 發信站: 批踢踢實業坊(ptt.cc), 來自: 114.44.244.29
※ 文章網址: https://www.ptt.cc/bbs/Python/M.1529654464.A.920.html
→
06/22 19:25,
6年前
, 1F
06/22 19:25, 1F
→
06/22 19:26,
6年前
, 2F
06/22 19:26, 2F
→
06/22 19:26,
6年前
, 3F
06/22 19:26, 3F
→
06/22 19:28,
6年前
, 4F
06/22 19:28, 4F
→
06/22 23:31,
6年前
, 5F
06/22 23:31, 5F
→
06/22 23:31,
6年前
, 6F
06/22 23:31, 6F
→
06/22 23:31,
6年前
, 7F
06/22 23:31, 7F
推
06/23 08:45,
6年前
, 8F
06/23 08:45, 8F
→
06/23 08:45,
6年前
, 9F
06/23 08:45, 9F
→
06/23 08:46,
6年前
, 10F
06/23 08:46, 10F
sys.path和relative import無關
→
06/23 08:47,
6年前
, 11F
06/23 08:47, 11F
我修改了上面project的架構,test資料夾通常會放在top-level。
我假設你說的debug是指開發的時候用來測的script,test是指拿來跑unit test的檔案。
Debug我會把他看成是用完就丟不會把他放進版控,所以不是放在最上層就是加`sys.path`
,不然就是用`PYTHONPATH`
test的話有蠻多種的,我是用pytest這個framework,然後執行的時候加`PYTHONPATH`
,像是
PYTHONPATH='./' pytest
另外,如果你寫好setup.py,那可以用tox這個工具幫你創好虛擬環境(而且一次跑多個
版本的python),安裝你寫的package然後跑你要的指令。所以open source常見的組
合就是
tox(創環境) + pytest(找test script來跑) + travis(免洗的標準環境)
當然小project可以不用這麼認真,原則就是自動化test,source code不要亂加東西。
最後請注意,以上講的都是用absolute import。Relative import是在你寫的package裡面
用,absolute import是用來找到package的root folder。
※ 編輯: ThxThx (114.44.244.29), 06/23/2018 11:39:54
推
06/23 15:41,
6年前
, 12F
06/23 15:41, 12F
推
06/24 14:30,
6年前
, 13F
06/24 14:30, 13F
→
06/24 14:31,
6年前
, 14F
06/24 14:31, 14F
就跟你設PATH一樣用冒號隔開
→
06/24 14:33,
6年前
, 15F
06/24 14:33, 15F
→
06/24 14:34,
6年前
, 16F
06/24 14:34, 16F
→
06/24 14:34,
6年前
, 17F
06/24 14:34, 17F
不像javascript,code愛放哪就放哪
import python module要先找到package(用absolute import)然後再用點(dot)往下鑽
relative import是給你在自己的package底下互相引用用的
→
06/24 14:41,
6年前
, 18F
06/24 14:41, 18F
→
06/24 14:45,
6年前
, 19F
06/24 14:45, 19F
→
06/24 14:45,
6年前
, 20F
06/24 14:45, 20F
→
06/24 14:47,
6年前
, 21F
06/24 14:47, 21F
→
06/24 14:47,
6年前
, 22F
06/24 14:47, 22F
→
06/24 14:48,
6年前
, 23F
06/24 14:48, 23F
→
06/24 14:49,
6年前
, 24F
06/24 14:49, 24F
→
06/24 14:50,
6年前
, 25F
06/24 14:50, 25F
→
06/24 14:51,
6年前
, 26F
06/24 14:51, 26F
→
06/24 14:52,
6年前
, 27F
06/24 14:52, 27F
設PYTHONPATH是在執行的時候修改sys.path啊:P
如果是這樣,那還不如加在sys.path裡面,至少不用記得執行的時候要加東西。
你會這樣放code可能也有其他的考量,我會這樣建議是覺得,隨意加sys.path也許沒有增
加現在的開發成本,但是絕對是增加維護的成本。哪個成本比較重要就要看你的選擇了。
回過頭來,現在假設問題就是crons/week和prediction_model裡的scripts都需要utils的
package。以前可能是每個script都寫很長,但現在如果變成
projects/
crons_week.py
crons_month.py (scripts)
predict.py
...
crons/
... (產生資料報表的功能)
prediction_model/
... (model本身)
utils/
... (其他共用的邏輯)
所有第一層scripts的功能是parse CLI arguments然後呼叫其他資料夾裡面的功能,不要
把複雜的邏輯寫在這裡面。也許這樣每個人就很容易了解這些檔案在做什麼、每個package
各自擁有什麼功能。
所以就是,我主張每個package把他看成是功能的集合/公約數。不一定要照做,不過
至少你現在知道absolute/relative import的原理了XD
→
06/24 14:53,
6年前
, 28F
06/24 14:53, 28F
※ 編輯: ThxThx (114.44.244.29), 06/25/2018 01:27:26
推
06/25 10:29,
6年前
, 29F
06/25 10:29, 29F
討論串 (同標題文章)
完整討論串 (本文為第 4 之 4 篇):
Python 近期熱門文章
PTT數位生活區 即時熱門文章