如何在Python中避免循环导入?

时间:2010-06-30 13:41:22

标签: python

我遇到循环导入问题。我有三个Python测试模块:robot_test.py这是我的主要脚本,然后是两个辅助模块,controller_test.py和servo_test.py。我的想法是我希望controller_test.py为我的微控制器定义一个类,并为servo_test.py定义一个类来为我的伺服器定义一个类。然后我想在robot_test.py中实例化这些类。这是我的三个测试模块:

""" robot_test.py """    
from pi.nodes.actuators.servo_test import Servo
from pi.nodes.controllers.controller_test import Controller

myController = Controller()
myServo = Servo()

print myController.ID, myServo.ID


""" controller_test.py """
class Controller():
    def __init__(self, id="controller"):
        self.ID = id


""" servo_test.py """
class Servo():
    def __init__(self, id="servo"):
        self.ID = id

如果我运行robot_test.py,我会得到预期的打印输出:

控制器伺服

然而,现在是扭曲。实际上,servo_test.py模块通过robot_test.py依赖于controller_test.py。这是因为我的伺服定义需要一个已经实例化的控制器对象才能实例化它们。但我想将所有初始实例保留在robot_test.py中。所以我尝试修改我的servo_test.py脚本如下:

""" servo_test.py """
from pi.nodes.robots.robot_test import myController
class Servo():
    def __init__(self, id="servo"):
        self.ID = id        
        print myController.ID

当然,我可以感觉到循环性会导致问题,当然,当我现在尝试运行robot_test.py时,我得到了错误:

ImportError:无法导入名称Servo

又是由servo_test.py返回错误引起的:

ImportError:无法导入名称myController

在C#中,我将myController和myServo定义为robot_test.py中的静态对象,然后我可以在其他类中使用它们。反正在Python中也一样吗?我找到的一个解决方法是将myController对象作为参数传递给Servo类,但我希望避免这样做。

谢谢!

3 个答案:

答案 0 :(得分:4)

  

我发现的一个解决方法是通过   myController对象到Servo   阶级作为一个论点,但我希望   为了避免这样做。

为什么你要避免它?这是一个关键设计模式的经典案例(也许是最初的四人组合杰作中最重要的一个),Dependency Injection

在初始化程序中具有依赖关系的DI实现备选方案包括使用setter方法(完成另一个关键的非Gof4 DP,two-phase construction,从__init__开始) - 避免了另一个循环问题与导入无关,当A的实例需要B B的实例需要A时,在每种情况下都要从逻辑上完成实例“初始化”。但是当你不需要两阶段构造时,初始化器是注入依赖关系的自然场所。

除了与打破循环性相关的优势之外,DI有助于重复使用(通过概括:例如,如果您需要拥有多个控制器和伺服器而不仅仅是其中一个,它可以让您轻松控制“配对”他们)和测试(例如,通过在其中注入另一个类,可以很容易地将每个类隔离用于测试目的。)

什么不喜欢?

答案 1 :(得分:0)

servo_test.py实际上不需要 myController,因为访问权属于一个函数。改为导入模块,并通过该模块访问myController

import pi.nodes.robots.robot_test as robot_test
class Servo():
    def __init__(self, id="servo"):
        self.ID = id        
        print robot_test.myController.ID

只要在myController实例化之前存在Servo,这将有效。

答案 2 :(得分:0)

将实例化的控制器对象作为init参数传递给Servo的实例化。

""" servo_test.py """
class Servo():
    def __init__(self,controller,id="servo"):
        self.ID = id
        self.ctrl = controller
        print self.ctrl.ID

""" robot_test.py """    
from pi.nodes.actuators.servo_test import Servo
from pi.nodes.controllers.controller_test import Controller

myController = Controller()
myServo = Servo(myController)