Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/282.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python:如何重构循环导入_Python_Refactoring - Fatal编程技术网

Python:如何重构循环导入

Python:如何重构循环导入,python,refactoring,Python,Refactoring,我有一件事你可以做engine.setState(),它将实例化你给它的类类型,并开始在新状态下运行 在SelectFileState中有一个按钮可以转到NewFileState,在NewFileState上有一个按钮可以返回到SelectFileState 现在,在SelectFileState的开头,我正在导入NewFileState(这样我可以稍后在类中执行engine.setState(NewFileState)。在NewFileState的开头,我也在导入SelectFileState

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

SelectFileState
中有一个按钮可以转到
NewFileState
,在
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)
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) ...
from states.mapping import STATE_MAPPING

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

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)
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) ...
from states.mapping import STATE_MAPPING

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

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

在Python中,导入不必出现在模块的开头。事实上,它们可以出现在函数中,因此在NewFileState.py中,您可以移动它们将SelectFileState导入NewFileState.create,您可以对SelectFileState.py进行类似的更改,因为您只需要在代码运行、类实例化和方法调用时使用交互类,这样就可以使父模块“state”可以使用类名并从中导入您的姓名:

状态。init.py

from states.selectfilestate import SelectFileState
from states.newfilestate import NewFileState
此时,两个子模块都将被初始化,即使在 执行主体时,他们将“看到”不完整版本的
状态
模块,此模块在此阶段不被访问 实际上是实例化的,
状态。_uinit_u; py
将完成执行, 对
状态的模块引用将指向完整的模块对象

在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)

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

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

下面是一个示例实现:

状态常数

# 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.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)
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) ...
from states.mapping import STATE_MAPPING

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

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)
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) ...
from states.mapping import STATE_MAPPING

def setState(class_key):
    obj = STATE_MAPPING[class_key]()
    # ... do other stuff ...
引擎。设置状态()


我想,但这只是一个快速解决方案还是“实际”解决方案?再说一次,我还没有看到你的代码,但这通常表明twain应该成为一个。真的没有其他好方法可以做到这一点。循环导入问题表示结构问题,而这样的问题正是我盲目尝试解决的。我只是尽管如此,我不确定这将如何帮助解释这个问题。这只是一个更模糊的解释。哦,这确实有帮助。从代码来看,合并这两个模块是非常明智的。它们不是1000行的整块,例如,导入是相当多余的。合并它们。我接受了你的答案但是,在这个特殊的例子中,我无法将每个状态合并到一个文件中。我如何处理其他不那么相互交织的状态呢?我在最初的帖子中提到了这一点(我不想这么做)。这是最简单的修复方法,并且很容易阅读和维护。不,导入应该在文件的开头(PEP 8)。仅仅因为它在20行文件中工作并不可取。请参阅以下答案:这说明了只导入名称空间/模块而不是使用
from..import
语法可能会有所帮助。请注意:您确实不需要方法。您所做的只是使代码更加冗余和缓慢。@pydsigner是的,我这样做。元素
\uuuu init\uuuu
例程做一些重要的事情,比如与引擎接口和设置一些变量。啊,但是您忘了自动继承父方法,包括。除非您正在调整某些内容,否则不需要重写它。@pydsigner-Doh!我已经知道了,但编写它已成为习惯。谢谢您指出这一点。