Re: [問題] 請問為何os.getcwd()不總在sys.path內?

作者: ThxThx (洗洗睡)   2018-06-22 16:01:01
原諒我只回關於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`
作者: uranusjr (←這人是超級笨蛋)   2018-06-22 19:25:00
Absolute import 那邊不太對, 它只看 sys.path, 不一定是先找 built-in (其實 Python 直譯器本身並不知道哪些模組是 built-in 哪些不是)不過這篇的概念很棒, 可惜我不是板主不能 m...
作者: ThxThx (洗洗睡)   2018-06-22 23:31:00
嗯!?那部份我是從https://tinyurl.com/qaasj5n 翻譯來我猜這裡的built in是指用C寫的那些modules,不過從來沒試過XD。
作者: os653   2018-06-23 08:45:00
想請教一下,那 debug 跟 test 的檔案要放哪裡?按照此篇所述,debug 跟 test 的檔案要放在 project 最上層如此才能不加工 sys.path 又能使用 relative import但這很奇怪呀,尤其 test 還有可能依測試目的放不同資料夾
作者: clsmbstu   2018-06-24 14:30:00
感謝解說!有幾個問題我想再請教一下:1. PYTHONPATH環境變數可以賦予數個不同的資料夾嗎?2. 如果我沒理解錯,看起來relative import只能寫在「會被其它script/module import的module」?在程式本身寫relative import的話,一定會因為碰到__main__而錯誤。BTW 對我來說 最常碰到的困擾倒不是因為debug或test檔案我在做的大多是data analyses,所以本來就會把檔案歸類成不同的資料夾,例如:projects/crons/month 是產生資料月報有關的檔案projects/crons/week 是產生資料週報有關的檔案projects/prediction_model 跟公司業務預測模型有關projects/connection 連接公司資料庫所需的packageprojects/utils 是資料前處理、資料清洗的package這種狀況下,relative import卻完全幫不上忙 @@又要不修改sys.path的話,只能讓PYTHONPATH指向多處?這也是為什麼我第一個問題那麼問Thank you!!!

Links booklink

Contact Us: admin [ a t ] ucptt.com