Python: How to refactor circular imports
我有一件事你可以做
在
现在,在
但是,这会创建一个循环导入,如其他一些文章中所述。有人说循环导入是设计不好的指标,应该重构。
我知道我可以在需要使用它之前通过导入EDOCX1[1]来解决这个问题,但我宁愿以正确的方式进行操作并重构它。
现在我想知道……你将如何重构它?
谢谢。
编辑:Pydsigner建议我将这两个文件合并为一个,因为它们彼此都非常相关。但是,我不能将每个具有循环依赖性的状态都放到一个文件中,因此必须有更好的方法来实现这一点。有什么想法吗?
2编辑:我现在通过不使用
代码:
选择文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | from states.state import State from states.newfilestate import NewFileState from elements.poster import Poster from elements.label import Label from elements.button import Button from elements.trifader import TriFader import glob import os class SelectFileState(State): def __init__(self, engine): super().__init__(engine) def create(self): self.engine.createElement((0, 0), Poster(self.engine.getImage('gui_loadsave')), 1) self.engine.createElement((168, 30), Label("Load a game", 40), 2) self.engine.createElement((400, 470), Button("New save", code=self.engine.createElement, args=((0, 0), TriFader(NewFileState, False), -240)), 3) ycounter = 150 globs = glob.glob("save\\*.mcw") for file in globs: self.engine.createElement((200, ycounter), Button(os.path.basename(file)[:-4]), 2) ycounter += 50 |
新文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | from states.state import State from states.selectfilestate import SelectFileState from elements.poster import Poster from elements.label import Label from elements.button import Button from elements.inputbox import InputBox from elements.trifader import TriFader class NewFileState(State): def __init__(self, engine): super().__init__(engine) def create(self): self.engine.createElement((0, 0), Poster(self.engine.getImage('gui_loadsave')), 1) self.engine.createElement((135, 30), Label("Make a new save", 40), 2) self.lvlname = self.engine.createElement((180, 212), InputBox(length=25, text="World name"), 2) self.engine.createElement((200, 240), Button(text="Ok", code=self.createSave, args=()), 2) def createSave(self): open("save\" + self.lvlname.getText() +".mcw", 'w') self.engine.createElement((0, 0), TriFader(SelectFileState), -240) |
如果看不到代码,最有意义的是合并两个文件。如果它们紧密地交织在一起,你可能会把它们放在一起,而不会有任何异常的地方。
在python中,导入不必出现在模块的开头。实际上,它们可以出现在函数中,因此在newfilestate.py中,可以将selectfilestate的导入移动到newfilestate.create中,并且可以对selectfilestate.py进行类似的更改。
您可以在字典映射中隐藏实际的类引用,而不是传递类引用,而是传递一个映射到实际类的常量值。它可以像dict一样保存在独立模块中,也可以包装在单独的StateManager类中,该类负责检索下一个状态。
这种方法的问题在于,您需要手动更新状态列表以及从常量到类引用的映射。
下面是一个示例实现:
康斯特
1 2 3 4 5 6 | # This module is states.const ( STATE_SELECT_FILE, STATE_NEW_FILE, ) = range(2) # manually update this number when you add/remove states |
状态映射
1 2 3 4 5 6 7 8 9 | # This module is states.mapping from states.const import * from states.newfilestate import NewFileState from states.selectfilestate import SelectFileState STATE_MAPPING = { STATE_SELECT_FILE : SelectFileState, STATE_NEW_FILE : NewFileState, } |
选择文件
1 2 3 | from states.const import STATE_NEW_FILE # ... snip ... ... TriFader(STATE_NEW_FILE, False) ... |
新文件
1 2 3 | from states.const import STATE_SELECT_FILE # ... snip ... ... TriFader(STATE_SELECT_FILE) ... |
发动机.设置状态(
1 2 3 4 5 | from states.mapping import STATE_MAPPING def setState(class_key): obj = STATE_MAPPING[class_key]() # ... do other stuff ... |
您可以在这里做的是,因为只有在代码运行、类被实例化和方法被调用时,您才需要交互类,这是为了使类名称可用于父模块-"状态",并从中导入您的名称:
状态
1 2 | from states.selectfilestate import SelectFileState from states.newfilestate import NewFileState |
此时,两个子模块都将被初始化,即使在他们将"看到"一个不完整版本的
在state.selectfilestate中:
1 2 3 | import states ... self.engine.createElement((0, 0), TriFader(states.SelectFileState), -240) |
在state.newfilestare上:
1 2 3 | import states ... self.engine.createElement((0, 0), TriFader(SelectFileState), -240) |