在Python中避免循环(循环)导入?

时间:2012-12-13 20:11:07

标签: python python-2.7

一种方法是使用import x,而不使用“from”关键字。那么你随处可以引用它们的命名空间。

还有其他方法吗?喜欢做类似于C ++ ifnotdef __b__ def __b__类型的事情吗?

3 个答案:

答案 0 :(得分:10)

将任何彼此依赖的模块合并到一个模块中。然后引入额外的模块来恢复旧名称。

如,

# a.py
from b import B

class A: whatever

# b.py
from a import A

class B: whatever

变为

# common.py
class A: whatever
class B: whatever

# a.py
from common import A

# b.py
from common import B

答案 1 :(得分:5)

循环导入是一种“代码气味”,并且通常(但并非总是)表明某些重构是合适的。例如,如果A.x使用B.yB.y使用A.z,那么您可以考虑将A.z移动到自己的模块中。

如果你认为你需要循环导入,那么我通常建议导入模块并引用具有完全限定名称的对象(即import A并使用A.x而不是{{1} })。

答案 2 :(得分:0)

如果您正在尝试from A import *,答案很简单:不要这样做。您通常假定执行import A并参考限定名称。

对于快速和肮脏的脚本以及交互式会话,这是一件非常合理的事情 - 但在这种情况下,您不会遇到循环导入。

在某些情况下,在实际代码中执行import *是有意义的。例如,如果你想隐藏一个复杂的模块结构,或者你动态生成的模块结构,或者在版本之间频繁更改的模块结构,或者如果你正在包装太深嵌套的其他人的包,import *可能有意义来自“包装器模块”或顶级包模块。但在这种情况下,您导入的任何内容都不会导入您。

事实上,我很难想象import *有必要保证任何情况,甚至可能存在循环依赖。

如果您正在进行from A import foo,可以采用相应方法(例如,import A然后foo = A.foo)。但你可能不想这样做。再次,考虑一下您是否真的需要将foo带入您的命名空间 - 限定名称是一个功能,而不是要解决的问题。

如果您正在执行from A import foo只是为了方便实现您的功能,因为A实际上是long_package_name.really_long_module_name而您的代码因为对{{1}的所有调用而无法读取},请记住,您始终可以long_package_name.really_long_module_name.long_class_name.class_method_that_puts_me_over_80_characters然后使用import long_package_name.really_long_module_name as P进行合格的通话。

(另外,请记住,为了方便实现,为了实现任何P,您可能需要确保指定from以确保导入的名称看起来不是命名空间的一部分如果有人通过互动会话对你进行了__all__。)

此外,正如其他人所指出的那样,大多数(但不是全部)循环依赖的情况都是设计糟糕的症状,并且以合理的方式重构模块将解决它。在极少数情况下,您确实需要将名称带入命名空间,并且一组循环模块实际上是最佳设计,一些人工重构可能仍然是比import *更好的选择。