簡體   English   中英

pip install -e,Python 路徑和命名空間包

[英]pip install -e, Python path and namespace packages

我有這樣的包布局

myproject/
    setup.py   # contains package info for "myproject" package
    myproject/ # contains various Python source files
    deploy/    # contains non-package Python scripts for deployment tools
    tests/ 
    ...

如果我發出pip install -e .從頂層myproject文件夾中。 (這是在 conda 環境中),然后路徑/path/to/myproject最終始終是sys.path的一部分。

例如,如果我創建了myproject存儲庫的新克隆並將其存儲在新文件夾中,例如myproject2 ,然后在該文件夾中的交互式解釋器中做一些工作,我發現sys.path仍然有/path/to/myproject在啟動時自動。

我的預感是這種情況以某種方式發生,因為pip install -e會將文件從/path/to/myproject符號鏈接到site-packages或其他合適的位置,並且 Python 中的模塊系統初始化必須在符號鏈接之后進行一些特殊處理,並且自動將源目錄添加到路徑中。

我遇到的問題是deploy/中的(非包)腳本使用絕對導入來引用同一文件夾中的其他腳本(因為它們打算從myproject的頂層執行),我該如何防止 Python而是只找到存在於使用pip install -e並因此出現在 Python 路徑上的myproject的特定克隆的此文件夾的副本?

添加

在這種情況下,命名空間包會發生什么也讓我感到困惑。 例如,如果deploy/文件夾沒有__init__.py文件,但您正在/path/to/myproject工作目錄中執行操作(或者在 Python 路徑中有該目錄),那么在 Python 3.3+ 中它將被視為可以跨目錄的命名空間包。

那么如果我兩者都有會發生什么

/path/to/myproject   # which has been installed with pip install -e
/path/to/myproject2  # not installed, extra clone of the same project

那么如果我在/path/to/myproject2處理deploy/腳本,它們最終是否會被視為一個名稱空間包,其中還包括/path/to/myproject/deploy/因為/path/to/myproject總是憑借pip install -e在 Python 路徑中?

然后最后一個問題是,這會對意外跨越兩個目錄的“巨型” deploy命名空間包內的絕對與相對導入和導入優先級產生什么影響。

sys.path的值有影響的是site-packages目錄中的easy-install.pth文件。 此效果不依賴於當前工作目錄。 我仍然不完全確定*.egg-link文件在site-packages目錄中究竟扮演什么角色(盡管它確實意味着,至少部分地,作為符號鏈接的獨立於平台的替代品)。

至於命名空間包......讓我們考慮以下目錄樹:

.
├── alfa
│   ├── bravo
│   │   ├── one.py
│   │   └── zero.py
│   └── zero.py
├── foo
│   ├── bar
│   │   ├── two.py
│   │   └── zero.py
│   └── zero.py
└── src
    ├── alfa
    │   ├── bravo
    │   │   ├── three.py
    │   │   └── zero.py
    │   └── zero.py
    └── foo
        ├── bar
        │   ├── four.py
        │   └── zero.py
        ├── __init__.py
        └── zero.py

所有*.py文件都包含以下內容:

print(__name__, __file__)

注意只有一個包初始化器src/foo/__init__.py

模塊alfa.bravo.onefoo.bar.two是可導入的,因為當前目錄總是在 Python 解釋器的搜索路徑( sys.path )上:

$ python3 -c 'import alfa.bravo.one'
alfa.bravo.one /home/sinoroc/workspace/so-59682278/alfa/bravo/one.py
$ python3 -c 'import foo.bar.two'
foo.bar.two /home/sinoroc/workspace/so-59682278/foo/bar/two.py

但是導入alfa.bravo.threefoo.bar.four是不可能的:

$ python3 -c 'import alfa.bravo.three'
Traceback (most recent call last):
  File "<string>", line 1, in <module>
ModuleNotFoundError: No module named 'alfa.bravo.three'
$ python3 -c 'import foo.bar.four'
Traceback (most recent call last):
  File "<string>", line 1, in <module>
ModuleNotFoundError: No module named 'foo.bar.four'

之所以如此,是因為它們位於src目錄中,而該目錄不在 Python 的路徑中:

$ python3 -c 'import sys; print(sys.path)'
['', '/usr/lib/python36.zip', '/usr/lib/python3.6', '/usr/lib/python3.6/lib-dynload', '/home/sinoroc/workspace/so-59682278/.venv/lib/python3.6/site-packages']

通過在解釋器的site-packages目錄中的.pth中寫入其位置,可以將目錄添加到 Python 的路徑中:

$ echo "${PWD}/src" > '.venv/lib/python3.6/site-packages/test.pth'
$ python3 -c 'import sys; print(sys.path)'
['', '/usr/lib/python36.zip', '/usr/lib/python3.6', '/usr/lib/python3.6/lib-dynload', '/home/sinoroc/workspace/so-59682278/.venv/lib/python3.6/site-packages', '/home/sinoroc/workspace/so-59682278/src']

現在可以導入alfa.bravo.threefoo.bar.four

$ python3 -c 'import alfa.bravo.three'
alfa.bravo.three /home/sinoroc/workspace/so-59682278/src/alfa/bravo/three.py
$ python3 -c 'import foo.bar.four'
foo /home/sinoroc/workspace/so-59682278/src/foo/__init__.py
foo.bar.four /home/sinoroc/workspace/so-59682278/src/foo/bar/four.py

由於命名空間包,模塊alfa.bravo.one仍然是可導入的:

$ python3 -c 'import alfa.bravo.one'
alfa.bravo.one /home/sinoroc/workspace/so-59682278/alfa/bravo/one.py

但是由於src目錄中的包foo有一個初始化器,所以foo不再是一個命名空間包並且模塊foo.bar.two不能被導入:

$ python3 -c 'import foo.bar.two'
foo /home/sinoroc/workspace/so-59682278/src/foo/__init__.py
Traceback (most recent call last):
  File "<string>", line 1, in <module>
ModuleNotFoundError: No module named 'foo.bar.two'

現在對於zero模塊來說,這有點令人驚訝。 當前目錄和src目錄中的模塊具有完全相同的導入路徑:

$ python3 -c 'import alfa.zero'
alfa.zero /home/sinoroc/workspace/so-59682278/alfa/zero.py
$ python3 -c 'import alfa.bravo.zero'
alfa.bravo.zero /home/sinoroc/workspace/so-59682278/alfa/bravo/zero.py
$ python3 -c 'import foo.zero'
foo /home/sinoroc/workspace/so-59682278/src/foo/__init__.py
foo.zero /home/sinoroc/workspace/so-59682278/src/foo/zero.py
$ python3 -c 'import foo.bar.zero'
foo /home/sinoroc/workspace/so-59682278/src/foo/__init__.py
foo.bar.zero /home/sinoroc/workspace/so-59682278/src/foo/bar/zero.py

如果沒有初始化包( alfa ),則導入當前工作目錄中的版本。 但是,如果有一個版本帶有初始化程序 ( foo ),那么這是導入的初始化包中的版本。

筆記

  • 蟒蛇 3.6.9

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM