Python:如何重构循环导入

时间:2012-11-13 02:14:18

标签: python refactoring

我有一件事你可以做engine.setState(<state class>)它会实例化你给它的类类型并开始在新状态下运行。

SelectFileState中,有一个按钮可以转到NewFileState,在NewFileState上,有一个按钮可以返回SelectFileState

现在,在SelectFileState的开头,我正在导入NewFileState(所以我可以稍后在课堂上engine.setState(NewFileState)。在NewFileState的开头,我我也导入了SelectFileState(所以我以后可以回到SelectFileState)。

但是,这会创建一个循环导入,如其他一些帖子中所述。有人说循环进口是指标设计不好,应该重构。

我知道我可以通过在我需要使用它之前导入SelectFileState来解决这个问题,但我宁愿以正确的方式做事并重构它。

现在我想知道..你怎么重构那个?

感谢。

修改的: Pydsigner建议我将两个文件合并为一个,因为它们彼此非常相关。但是,我不能将具有循环依赖关系的每个状态放入一个文件中,因此必须有一个更好的方法。有什么想法吗?

2Edit 我现在通过不使用from x import y语法来绕过这个问题,而只是做import x。这不是一个更好的解决方案,我想知道解决这种事情的“Pythonic”方法。只是将文件合并在一起不能永远解决。

代码:

SelectFileState

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

NewFileState

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)

4 个答案:

答案 0 :(得分:3)

在没有看到代码的情况下,最有意义的是合并这两个文件。如果它们紧密交织在一起,你可能会将它们组合在一起而不会有任何奇怪的不合适的地方。

答案 1 :(得分:2)

在Python中,导入不必出现在模块的开头。实际上它们可以出现在函数中,因此在NewFileState.py中你可以将SelectFileState的导入移动到NewFileState.create中,你可以对SelectFileState.py进行类似的更改

答案 2 :(得分:0)

你可以在这里做什么,因为你只需要代码运行时的互惠类,实例化类和调用方法,就是让类名可用于父模块 - “状态”并导入你的那里的名字:

状态。的初始化的.py

from states.selectfilestate import SelectFileState
from states.newfilestate import NewFileState

此时两个子模块都将被初始化 - 即使在此期间 执行身体他们将“看到”states的不完整版本 模块,此阶段未访问此模块。当任何一个classess 实际上是实例化的,states.__init__.py将完成执行, 对states的模块引用将指向完整的模块对象。

在state.selectfilestate中:

import states
...
        self.engine.createElement((0, 0), TriFader(states.SelectFileState), -240)

在state.newfilestare上:

import states
...
        self.engine.createElement((0, 0), TriFader(SelectFileState), -240)

答案 3 :(得分:0)

您可以在字典映射中隐藏实际的类引用,而不是传递类引用,而是传递一个映射到真实类的常量值。这可以作为独立模块中的dict保存,也可以包装在处理检索下一个状态的单独StateManager类中。

这种方法的问题是你需要手动更新状态列表和从常量到类引用的映射。

以下是一个示例实现:

<强> states.const

# This module is states.const

(
    STATE_SELECT_FILE,
    STATE_NEW_FILE,
) = range(2) # manually update this number when you add/remove states

<强> states.mapping

# 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,
}

<强> SelectFileState

from states.const import STATE_NEW_FILE
# ... snip ...
... TriFader(STATE_NEW_FILE, False) ...

<强> NewFileState

from states.const import STATE_SELECT_FILE
# ... snip ...
... TriFader(STATE_SELECT_FILE) ...

<强> engine.setState()

from states.mapping import STATE_MAPPING

def setState(class_key):
    obj = STATE_MAPPING[class_key]()
    # ... do other stuff ...