尽管绝对进口,但循环进口
Circular import despite absolute imports
我在 Python 3.9 中遇到循环导入问题。
我知道有很多关于这个主题的文章、问题和答案,我确实阅读了很多关于如何规避的文章,但我无法弄清楚为什么它会发生在我的案例中。据我所知,可以通过绝对导入来规避循环导入:
这是我的堆栈跟踪:
partially initialized module 'myproject.myapp.service.linepattern.corner' has no attribute 'Corner' (most likely due to a circular import)
File "/mnt/d/User/Programming/MyProject/myproject/myapp/service/linepattern/line.py", line 8, in Line
def __init__(self, cornerRight: cc.Corner, cornerLeft: cc.Corner) -> None:
File "/mnt/d/User/Programming/MyProject/myproject/myapp/service/linepattern/line.py", line 7, in <module>
class Line(ABC):
File "/mnt/d/User/Programming/MyProject/myproject/myapp/service/linepattern/corner.py", line 2, in <module>
import myproject.myapp.service.linepattern.line as cl
File "/mnt/d/User/Programming/MyProject/myproject/myapp/service/linepattern/cornermanager.py", line 2, in <module>
import myproject.myapp.service.linepattern.corner as cc
File "/mnt/d/User/Programming/MyProject/myproject/tests/myapp/test_cornermanager.py", line 3, in <module>
import myproject.myapp.service.linepattern.cornermanager as cm
这是我的文件层次结构
/mnt/d/User/Programming/MyProject
├── manage.py
├── myproject
│ ├── myapp
│ │ ├── __init__.py
│ │ ├── service
│ │ │ └── linepattern
│ │ │ ├── cornermanager.py
│ │ │ ├── corner.py
│ │ │ ├── line.py
│ │ │ ├── __init__.py
│ ├── settings.py
│ ├── tests
│ │ ├── myapp
│ │ │ ├── __init__.py
│ │ │ └── test_cornermanager.py
最后是我的代码
cornermanager.py
import myproject.myapp.service.linepattern.corner as cc
class CornerManager:
def __init__(self) -> None:
self.cornerList: List[cc.Corner]
for i in range(1, 2):
self.cornerList.append(cc.Corner(i, self))
for corner in self.cornerList:
corner.initializeLines()
def corner(self, cornerNr: int) -> cc.Corner:
return self.cornerList[cornerNr - 1]
corner.py
import myproject.myapp.service.linepattern.cornermanager as cm
import myproject.myapp.service.linepattern.line as cl
class Corner:
def __init__(self, cornerNumber: int, cornerManager: cm.CornerManager) -> None:
self.cornerNumber = cornerNumber
self.cornerManager = cornerManager
self.lineSet: Set[cl.Line]
def initializeLines(self) -> None:
#Add lines to the corner including its neighbor
if self.cornerNumber == 1:
self.lineSet.add(cl.Line(self, self.cornerManager.corner(2)))
elif self.cornerNumber == 2:
self.lineSet.add(cl.Line(self, self.cornerManager.corner(2)))
def addLine(self, line: cl.Line) -> None:
#Remove line from both corners
for corner in cl.cornerPair():
corner.lineSet.add(line)
def removeLine(self, line: cl.Line) -> None:
#Remove line from both corners
for corner in cl.cornerPair():
corner.lineSet.remove(line)
line.py
import myproject.myapp.service.linepattern.corner as cc
class Line:
def __init__(self, cornerRight: cc.Corner, cornerLeft: cc.Corner) -> None:
self.rightCorner = cornerRight
self.leftCorner = cornerLeft
def cornerPair(self) -> Tuple[cc.Corner, cc.Corner]:
#Return both corners
return (self.rightCorner, self.leftCorner)
使用问题中的代码(三个独立的模块),通过在每个文件的顶部包含以下代码应该能够解决问题:
from __future__ import annotations
简而言之,此代码会将注释视为 strings
。您可以在以下位置阅读更多相关信息: and Evaluation of annotations
.
对于错误,这实际上是 Python 执行您的模块的方式(从 cornermanager.py
开始):
import corner
。使用此 Python 首先将模块保存在其内部模块 (sys.modules
) 之前 运行 导入的模块代码。
- 在
corner.py
本身,前两行是import statement
,所以让我们从import cornermanager
开始。同样,Python 将模块保存在其内部模块中,然后执行 cornermanager
. 中的代码
- 回到
cornermanager.py
。我们知道这个模块的第一行是 import corner
,但是因为 Python 已经在它的内部模块中保存了这个模块 (corner
),所以它不会第二次导入它。也就是说,Python 跳过它并执行此行下面的代码。有趣的是,因为 corner
除了第一行 (import cornermanager
) 之外还没有执行它的所有代码,所以尝试获取它的 Corner class
不会成功。
我在 Python 3.9 中遇到循环导入问题。 我知道有很多关于这个主题的文章、问题和答案,我确实阅读了很多关于如何规避的文章,但我无法弄清楚为什么它会发生在我的案例中。据我所知,可以通过绝对导入来规避循环导入:
这是我的堆栈跟踪:
partially initialized module 'myproject.myapp.service.linepattern.corner' has no attribute 'Corner' (most likely due to a circular import)
File "/mnt/d/User/Programming/MyProject/myproject/myapp/service/linepattern/line.py", line 8, in Line
def __init__(self, cornerRight: cc.Corner, cornerLeft: cc.Corner) -> None:
File "/mnt/d/User/Programming/MyProject/myproject/myapp/service/linepattern/line.py", line 7, in <module>
class Line(ABC):
File "/mnt/d/User/Programming/MyProject/myproject/myapp/service/linepattern/corner.py", line 2, in <module>
import myproject.myapp.service.linepattern.line as cl
File "/mnt/d/User/Programming/MyProject/myproject/myapp/service/linepattern/cornermanager.py", line 2, in <module>
import myproject.myapp.service.linepattern.corner as cc
File "/mnt/d/User/Programming/MyProject/myproject/tests/myapp/test_cornermanager.py", line 3, in <module>
import myproject.myapp.service.linepattern.cornermanager as cm
这是我的文件层次结构
/mnt/d/User/Programming/MyProject
├── manage.py
├── myproject
│ ├── myapp
│ │ ├── __init__.py
│ │ ├── service
│ │ │ └── linepattern
│ │ │ ├── cornermanager.py
│ │ │ ├── corner.py
│ │ │ ├── line.py
│ │ │ ├── __init__.py
│ ├── settings.py
│ ├── tests
│ │ ├── myapp
│ │ │ ├── __init__.py
│ │ │ └── test_cornermanager.py
最后是我的代码
cornermanager.py
import myproject.myapp.service.linepattern.corner as cc
class CornerManager:
def __init__(self) -> None:
self.cornerList: List[cc.Corner]
for i in range(1, 2):
self.cornerList.append(cc.Corner(i, self))
for corner in self.cornerList:
corner.initializeLines()
def corner(self, cornerNr: int) -> cc.Corner:
return self.cornerList[cornerNr - 1]
corner.py
import myproject.myapp.service.linepattern.cornermanager as cm
import myproject.myapp.service.linepattern.line as cl
class Corner:
def __init__(self, cornerNumber: int, cornerManager: cm.CornerManager) -> None:
self.cornerNumber = cornerNumber
self.cornerManager = cornerManager
self.lineSet: Set[cl.Line]
def initializeLines(self) -> None:
#Add lines to the corner including its neighbor
if self.cornerNumber == 1:
self.lineSet.add(cl.Line(self, self.cornerManager.corner(2)))
elif self.cornerNumber == 2:
self.lineSet.add(cl.Line(self, self.cornerManager.corner(2)))
def addLine(self, line: cl.Line) -> None:
#Remove line from both corners
for corner in cl.cornerPair():
corner.lineSet.add(line)
def removeLine(self, line: cl.Line) -> None:
#Remove line from both corners
for corner in cl.cornerPair():
corner.lineSet.remove(line)
line.py
import myproject.myapp.service.linepattern.corner as cc
class Line:
def __init__(self, cornerRight: cc.Corner, cornerLeft: cc.Corner) -> None:
self.rightCorner = cornerRight
self.leftCorner = cornerLeft
def cornerPair(self) -> Tuple[cc.Corner, cc.Corner]:
#Return both corners
return (self.rightCorner, self.leftCorner)
使用问题中的代码(三个独立的模块),通过在每个文件的顶部包含以下代码应该能够解决问题:
from __future__ import annotations
简而言之,此代码会将注释视为 strings
。您可以在以下位置阅读更多相关信息:Evaluation of annotations
.
对于错误,这实际上是 Python 执行您的模块的方式(从 cornermanager.py
开始):
import corner
。使用此 Python 首先将模块保存在其内部模块 (sys.modules
) 之前 运行 导入的模块代码。- 在
corner.py
本身,前两行是import statement
,所以让我们从import cornermanager
开始。同样,Python 将模块保存在其内部模块中,然后执行cornermanager
. 中的代码
- 回到
cornermanager.py
。我们知道这个模块的第一行是import corner
,但是因为 Python 已经在它的内部模块中保存了这个模块 (corner
),所以它不会第二次导入它。也就是说,Python 跳过它并执行此行下面的代码。有趣的是,因为corner
除了第一行 (import cornermanager
) 之外还没有执行它的所有代码,所以尝试获取它的Corner class
不会成功。