在我的项目中,我使用模块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.我怎样才能打败这种循环导入?
答案 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
函数,以允许延迟提供程序初始化。这种解耦使得更容易来测试和模拟单独的提供程序,并为自定义留出更多空间。此外,如果您需要将一个提供程序的扩展行为放在另一个提供程序中,则类对象将其状态存储在中,而不是模块级别。这样,您实际上可以从其他提供程序继承,而不必担心任何子提供程序将修改独立的基本提供程序的内部。