8

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

里面有SelectFileState一个按钮可以去NewFileState,on NewFileState,有一个按钮可以返回SelectFileState

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

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

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

现在我想知道..你会如何重构它?

谢谢。

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

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

编码:

选择文件状态

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

新文件状态

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

4 回答 4

3

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

于 2012-11-13T02:18:05.467 回答
2

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

于 2012-11-13T02:38:09.943 回答
0

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

状态。初始化.py

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

此时,两个子模块都将被初始化——即使在执行主体期间他们将“看到”模块的不完整版本,但states 在此阶段不会访问该模块。当任何一个类被实际实例化时,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)
于 2012-11-13T02:54:44.967 回答
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

状态映射

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

选择文件状态

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

新文件状态

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

引擎.setState()

from states.mapping import STATE_MAPPING

def setState(class_key):
    obj = STATE_MAPPING[class_key]()
    # ... do other stuff ...
于 2012-11-13T04:04:30.210 回答