簡體   English   中英

Python 導入失敗。 相對導入、包識別、__init__.py、__package__、__all__

[英]Python Imports failing. Relative imports, package recognition, __init__.py , __package__, __all__

我一直在閱讀很多線程,與此問題相關的 PEP 文章,大約有 4 篇,但沒有一篇文章在某些方面給出了明確的想法,我仍然無法進行相對導入。

事實上,我的主包的內容根本沒有列出。

再版。 我修改了所有帖子,它太復雜了,問題很多。

C:/test/我有這個包:

Package/ (FOLDER 2)
    __init__.py
    moduleA.py
    moduleB.py
  • moduleA導入moduleB ,反之亦然。
  • __init__.py為空

我的流程:

  1. 我將C:/test/添加到sys.path
  2. import Package (WORKS)
  3. dir(Package)不列出包內的任何模塊。
  4. 包是: <module 'Package' from C:/test/Package/_init_.py>
  5. __file__是 Package 下的 init 文件
  6. __name__Package
  7. __package__是一個空字符串
  8. __path__C:/test/Package

測試 1 - 版本 1:在moduleA我有from Package import moduleB

我明白了:

>>> import Package.moduleA
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "C:/test\Package\moduleA.py", line
    from Package import moduleB
  File "C:/test\Package\moduleB.py", line
    from Package import moduleA
ImportError: cannot import name moduleA

它不起作用,因為moduleA不是Package一部分。 所以Package不被識別為包?


測試 1 - 版本 2:在moduleAfrom . import moduleB from . import moduleB

不行,同樣的錯誤


測試 1 - 版本 3:在moduleAimport Package.moduleB

有用。

之后,運行:

>>> dir(Package.moduleB)
['Package', '__builtins__', '__doc__', '__file__', '__name__', '__package__']
>>> Package.moduleB.Package
<module 'Package' from 'C:/prueba\Package\__init__.py'>
>>> dir(Package)
['__builtins__', '__doc__', '__file__', '__name__', '__package__', '__path__', 'moduleA', 'moduleB']

所以現在, Package.moduleBPackage作為變量 令人驚訝的是, Package看起來像一個合適的包,並且包含兩個模塊。

事實上,在版本 1 和版本 2 中執行任何導入現在都可以工作,因為現在moduleAmoduleBPackage一部分。


問題:

1) 為什么Package不被識別為包? 是嗎? 它不應該包含所有子模塊嗎?

2) 為什么運行import Package.moduleAmoduleA生成Package

3) 為什么運行import Package.moduleA會將moduleA添加到Package而它之前沒有?

4) 空的__init__.py文件和非空的__init__.py文件對此有影響嗎?

5) 定義一個包含['moduleA', 'moduleB']__all__變量在這里有什么作用嗎?

6) 如何使 init 文件加載兩個子模塊? 我應該在里面import Package.moduleAPackage.moduleB嗎?...我不能像import .moduleA as moduleA或類似的東西那樣做嗎? (如果Package的名稱發生變化怎么辦?)

7) 包變量上的空字符串有影響嗎? 如果我們想讓它識別自己,我們應該更改它的內容...... __package__應該與__name__相同,或者這就是 PEP 所說的。 但是這樣做沒有用:

if __name__ == "__main__" and __package__ is None:
    __package__ = "Package"

這是一個循環依賴問題。 它與此問題非常相似,但不同之處在於您嘗試從包中導入模塊,而不是從模塊中導入類。 在這種情況下,最好的解決方案是重新考慮您的代碼,以便不需要循環依賴。 將任何常用函數或類移出包中的第三個模塊。

擔心__package__是一個紅鯡魚。 當你的包成為一個合適的包時,python 導入系統會適當地設置它。

問題是moduleAmoduleB僅在成功導入后才放入package 但是,由於moduleAmoduleB都在導入過程中,因此它們在package無法看到彼此。 當您繞過相對導入機制時,絕對導入部分解決了問題。 但是,如果您的模塊在初始化期間需要彼此的一部分,則程序將失敗。

如果var = ...行被刪除,以下代碼將起作用。

包.moduleA

import package.moduleB
def func():
    return 1

包.moduleB

import package.moduleA
var = package.moduleA.func() # error, can't find moduleA

破損包裹示例

包.moduleA

from . import moduleB
def depends_on_y():
    return moduleB.y()
def x():
    return "x"

包.moduleB

from . import moduleA
def depends_on_x():
    return moduleA.x()
def y():
    return "y"

將公共部分提取到包中的單獨模塊中的示例

包.common

def x():
    return "x"
def y():
    return "y"

包.moduleA

from .common import y
def depends_on_y():
    return y()

包.moduleB

from .common import x
def depends_on_x():
    return x()

這是 Python 3.5 之前版本中存在的 Python 錯誤。 請參閱問題 992389 (多年)和問題 17636 ,其中修復了該問題的常見情況。

在 Python 3.5 中修復之后,一個顯式的相對導入,如from . import moduleA 從包內的模塊中from . import moduleA Package將在sys.modules檢入Package.moduleA ,如果moduleA尚不存在於Package ,則moduleA 由於模塊對象在開始加載之前添加到sys.modules ,但直到加載完成后才添加到Package.__dict__ ,因此這通常可以解決問題。

使用from package import *進行循環導入仍然可能存在問題,但在issue 23447 (我為其貢獻了補丁)中,決定修復更模糊的極端情況不值得額外的代碼復雜性。

圓形進口通常是不良設計的標志。 您可能應該將相互依賴的代碼部分重構為一個由其他模塊導入的單個實用程序模塊,或者您應該將兩個單獨的模塊合並為一個。

暫無
暫無

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

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