Phi*_*ier 8 python import circular-dependency
首先:我知道已经有很多关于循环进口主题的问题和答案.
答案或多或少是:"正确设计模块/类结构,您不需要循环导入".那是真实的.我努力为我当前的项目做一个合适的设计,我认为我是成功的.
但我的具体问题如下:我需要在模块中进行类型检查,该模块已由包含要检查的类的模块导入.但这会引发导入错误.
像这样:
foo.py:
from bar import Bar
class Foo(object):
def __init__(self):
self.__bar = Bar(self)
Run Code Online (Sandbox Code Playgroud)
bar.py:
from foo import Foo
class Bar(object):
def __init__(self, arg_instance_of_foo):
if not isinstance(arg_instance_of_foo, Foo):
raise TypeError()
Run Code Online (Sandbox Code Playgroud)
解决方案1:如果我修改它以通过字符串比较检查类型,它将起作用.但我真的不喜欢这个解决方案(对于简单的类型检查,字符串比较相当昂贵,并且在重构时可能会遇到问题).
bar_modified.py:
from foo import Foo
class Bar(object):
def __init__(self, arg_instance_of_foo):
if not arg_instance_of_foo.__class__.__name__ == "Foo":
raise TypeError()
Run Code Online (Sandbox Code Playgroud)
解决方案2:我也可以将这两个类打包成一个模块.但我的项目有许多不同的类,如"Bar"示例,我想将它们分成不同的模块文件.
在我自己的2个解决方案对我来说没有选择之前:有没有人为这个问题找到更好的解决方案?
最好的解决方案是不检查类型。
另一种解决方案是不创建实例或完全不引用,Foo或者Bar直到两个类均被加载。如果首先加载第一个模块,则在执行该语句之前不要创建Bar或引用。同样,如果首先加载第二个模块,则在语句执行后才创建或引用。Barclass FooFooFooclass Bar
这基本上是的来源,ImportError如果改为使用“ import foo”和“ import bar”,并foo.Foo在现在使用的位置Foo和bar.Bar现在使用的位置使用,则可以避免这种情况Bar。这样一来,您将不再在创建Foo或之前引用它们中的任何一个Bar,而希望在创建两者之前都不会引用它们(否则您将获得AttributeError)。
你可以编程interface(ABC - python中的抽象基类),而不是特定的类型Bar.这是解决许多语言中的包/模块相互依赖性的经典方法.从概念上讲,它也应该导致更好的对象模型设计.
在你的情况下,你将IBar在一些其他模块中定义接口(甚至在包含Foo类的模块中 - 取决于它的用法abc).你的代码看起来像这样:
foo.py:
from bar import Bar, IFoo
class Foo(IFoo):
def __init__(self):
self.__bar = Bar(self)
# todo: remove this, just sample code
f = Foo()
b = Bar(f)
print f
print b
x = Bar('do not fail me please') # this fails
Run Code Online (Sandbox Code Playgroud)
bar.py:
from abc import ABCMeta
class IFoo:
__metaclass__ = ABCMeta
class Bar(object):
def __init__(self, arg_instance_of_foo):
if not isinstance(arg_instance_of_foo, IFoo):
raise TypeError()
Run Code Online (Sandbox Code Playgroud)