模块循环导入

时间:2013-09-27 09:30:06

标签: python importerror python-import

在我的项目中,我使用模块interaction,其中包含一些“接口”,用于访问系统功能。例如,我有2个模块实现不同的接口,其中一个依赖于其他接口。

module1.py

value = 5

def init():
    pass

def provide_int():
    global value
    return value

module2.py

def init():
    import interaction
    global value
    value = str(interaction.int_provider.provide_int())

def provide_string():
    global value
    return value

所以我想以同样的方式使用它:

interaction.py

from importlib import import_module

globals()['int_provider'] = import_module('module1')
globals()['int_provider'].init()
globals()['str_provider'] = import_module('module2')
globals()['str_provider'].init()

因此在初始化module2(调用init函数)期间,由于循环导入,我得到一个ImportError。 这个例子当然是合成的,但共同的状态是相同的。

我有两个问题:
1.使用像我的interaction.py代理接口的“全局”模块是否正确?
2.我怎样才能打败这种循环导入?

2 个答案:

答案 0 :(得分:0)

我建议取消init函数并使provide_string()函数在首次调用时设置其值。因为在模块加载时很少发生,所以模块相互引用不会出现问题。此外,您可以使用常规导入interaction关键字来简化as模块:

iteraction.py:

 import module1 as int_provider
 import module2 as string_provider

module1.py:

 value = 5

 def provide_int():
     return value # no global statement necessary, since we don't assign to value

module2.py:

 value = None # this will be set up after the first call to provide_string

 def provide_string():
     global value # global is needed, since we may assign a new string to value
     if value is None:
         import interaction
         value = str(interaction.int_provider.provide_int())
     return value

答案 1 :(得分:0)

如何打败此循环导入?

您可以使用像django.utils.functional.SimpleLazyObject之类的东西来使用延迟创建的提供程序。这样,您将在访问它的任何属性时初始化提供程序。您必须记住记住 SimpleLazyObject中的结果,因为每次传递的函数都会重新评估

用法:

def init_str_provider():
    if not hasattr(init_str_provider, 'provider'):
        init_str_provider.provider = import_module('module2')
        init_str_provider.provider.init()
    return init_str_provider.provider

str_provider = SimpleLazyObject(init_str_provider)

使用代理接口的interaction.py之类的“全局”模块是否正确?

如果我要用接口创建这样的结构,我宁愿选择:

  • interfaces.py
  • 中的提供者类注册方法
  • 使用类来表示提供者(由于继承更容易接口!)。
  • get_provider(name)中提供interfaces.py函数,以允许延迟提供程序初始化。

这种解耦使得更容易来测试和模拟单独的提供程序,并为自定义留出更多空间。此外,如果您需要将一个提供程序的扩展行为放在另一个提供程序中,则类对象将其状态存储在中,而不是模块级别。这样,您实际上可以从其他提供程序继承,而不必担心任何子提供程序将修改独立的基本提供程序的内部。

相关问题