首页 > 解决方案 > 填充的 __init__ 似乎阻止访问同一包中的模块

问题描述

在一个项目中,一个模块moduleA需要访问moduleB同一子包中的模块packageA(在 package 中project)。此访问失败,当__init__.py子包的子包packageA填充了import .. as ..语句,而__init__py包项目为空时。

为什么填充__init__.py(看似)阻止来自此(相同包)模块的访问 - 而 PyCharm 似乎仍然从自动完成和突出显示的角度接受它?抛出的AttributeError建议表明,该import .. as ..语句使解释器相信子包是一个属性,而不是一个包——尽管存在一个__init__.py.

文件结构

├── ProjectA
│   ├── src
│   │   ├── project
│   │   │   ├── __init__.py
│   │   │   ├── packageA
│   │   │   │   ├── __init__.py
│   │   │   │   ├── moduleA.py
│   │   │   │   ├── moduleB.py

代码示例 1

# ProjectA / src / project / __init__.py
(empty)

# packageA / __init__.py
(empty)

# packageA / moduleA.py
import project.packageA.moduleB as dummy

class A:
    pass

class B:
    pass

# packageA / moduleB.py
def method():
    pass

代码执行1

# jupyter stated in 'C:\\Users\\username\\Desktop\\devenv\\'
# notebook located in 'C:\\Users\\username\\Desktop\\devenv\\dev\\'
import sys
sys.path
# output:
# ['C:\\src\\ProjectA',
#  'C:\\src\\ProjectA\\src',
#  'C:\\Users\\username\\Desktop\\devenv\\dev',
#  'C:\\ProgramData\\Anaconda3\\envs\\myenv\\python36.zip',
#  'C:\\ProgramData\\Anaconda3\\envs\\myenv\\DLLs',
#  'C:\\ProgramData\\Anaconda3\\envs\\myenv\\lib',
#  'C:\\ProgramData\\Anaconda3\\envs\\myenv',
#  '',
#  'C:\\ProgramData\\Anaconda3\\envs\\myenv\\lib\\site-packages',
#  'C:\\ProgramData\\Anaconda3\\envs\\myenv\\lib\\site-packages\\win32',
#  'C:\\ProgramData\\Anaconda3\\envs\\myenv\\lib\\site-packages\\win32\\lib',
#  'C:\\ProgramData\\Anaconda3\\envs\\myenv\\lib\\site-packages\\Pythonwin',
#  'C:\\ProgramData\\Anaconda3\\envs\\myenv\\lib\\site-packages\\IPython\\extensions',
#  'C:\\Users\\username\\.ipython']

from project.packageA.moduleA import A, B
# no error(s)

代码示例 2

第一个替代填充packageA / __init__.py

# packageA / __init__.py
from .moduleA import A, B
import .moduleB as dummy

第二种替代填充packageA / __init__.py

# packageA / __init__.py
from project.packageA.moduleA import A, B
import project.packageA.moduleB as dummy

代码执行2

from project.packageA.moduleA import A, B
AttributeError                            Traceback (most recent call last)
<ipython-input-1-61a791f79421> in <module>
----> 1 import project.packageA.moduleA.moduleB

C:\src\ProjectA\src\project\packageA\__init__.py in <module>
----> 1 from .moduleA import A, B
      2 from .moduleB import *

C:\src\ProjectA\src\project\packageA\moduleA.py in <module>
---> 1 import project.packageA.moduleB as dummy
     2 
     3 class A:

AttributeError: module 'project' has no attribute 'packageA'

解决方案

我在Stack Overflow: Imports in __init__.pyand import asstatement中找到了解决方案

将导入packageA / __init__.py从更改import .. asfrom xx import .. as做到了这一点:

# packageA / __init__.py
from project.packageA.moduleA import A, B
from project.packageA import moduleB as dummy

谁能帮我理解,为什么 import xx as 和 from xx import xx as 工作方式不同,当涉及到子包时——特别是在这种情况下,包__init__.py是空的,但子包__init__.py是填充的?

标签: pythonimportmodulepackageinit

解决方案


这种行为实际上不能用预期的后端机制的任何特性来描述:该行为与任何文档都不匹配,例如PEP 0221。因此,该import .. as ..语句是无效的。这个错误似乎已经用Python 3.7 修复了(我一直在运行 3.69)


推荐阅读