今天我遇到了一个非常令人惊讶的相对进口行为(不幸的是,经过将近4个小时的头发拉出来)。
我一直认为如果你在名为“package”的软件包中的模块名称“module_a.py”中有“Class A”,你可以等效地使用它们:
from package.module_a import ClassA
或
from module_a import ClassA
只要您从“package”中的模块导入即可。我理解这是相对重要的。
直到今天,当我需要检查A类对象的实例时,我才遇到问题,我很惊讶地发现了一种非常不寻常的行为。
请考虑以下事项:
class ClassA(object):
pass
def check_from_module_a(obj):
print 'from module_a'
print '-------------'
print 'class is:', ClassA
print 'object is', type(obj)
print 'is obj a ClassA:', isinstance(obj, ClassA)
from package.module_a import ClassA
from module_a import check_from_module_a
a = ClassA()
check_from_module_a(a)
print ' '
print 'from module_b'
print '-------------'
print 'class is:', ClassA
print 'object is', type(a)
print 'is obj a ClassA:', isinstance(a, ClassA)
现在执行module_b.py时,你得到:
from module_a
-------------
class is: <class 'module_a.ClassA'>
object is <class 'package.module_a.ClassA'>
is obj a ClassA: False
from module_b
-------------
class is: <class 'package.module_a.ClassA'>
object is <class 'package.module_a.ClassA'>
is obj a ClassA: True
我已经遵循逻辑,现在看看为什么会发生这种情况 - 这并不是很明显,因为我认为ClassA的绑定是相同的,无论绝对或相对导入。这给我带来了一个非常讨厌的错误,很难隔离。
我的问题:
这是预期的行为吗?
如果这是它应该工作的合理方式 - 那么我不清楚为什么我会使用相对导入,如果它们与绝对导入不兼容(在上面意义上)。这里有一个很好的解释,我错过了吗?
我总是假设当子包结构可能被移动时,相对导入在大型重构中提供了额外的便利。这是相对进口的主要好处吗?
答案 0 :(得分:4)
由于隐式相对导入导致了问题,因此它们已在Python 3中删除。您通常不会使用它们获得预期的行为。有关讨论,请参阅PEP-328。如果定义与基本(库存)模块同名的子包名称,则尤其如此。
答案 1 :(得分:0)
(1)是的,这是预期的行为。
(2)明确的相对导入是
from .module_a import ClassA
,而不是
from module_a import ClassA
可以是相对的也可以是绝对的,并且可以在顶级包和模块之间产生冲突。
(3)是的,这是相对进口的优势之一。主要好处可能是必须输入更少:)