Python中意外的相对导入行为

时间:2011-05-04 04:28:02

标签: python python-import

今天我遇到了一个非常令人惊讶的相对进口行为(不幸的是,经过将近4个小时的头发拉出来)。

我一直认为如果你在名为“package”的软件包中的模块名称“module_a.py”中有“Class A”,你可以等效地使用它们:

from package.module_a import ClassA

from module_a import ClassA

只要您从“package”中的模块导入即可。我理解这是相对重要的。

直到今天,当我需要检查A类对象的实例时,我才遇到问题,我很惊讶地发现了一种非常不寻常的行为。

请考虑以下事项:

包/ module_a.py

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)

包/ module_b.py

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的绑定是相同的,无论绝对或相对导入。这给我带来了一个非常讨厌的错误,很难隔离。

我的问题:

  1. 这是预期的行为吗?

  2. 如果这是它应该工作的合理方式 - 那么我不清楚为什么我会使用相对导入,如果它们与绝对导入不兼容(在上面意义上)。这里有一个很好的解释,我错过了吗?

  3. 我总是假设当子包结构可能被移动时,相对导入在大型重构中提供了额外的便利。这是相对进口的主要好处吗?

2 个答案:

答案 0 :(得分:4)

由于隐式相对导入导致了问题,因此它们已在Python 3中删除。您通常不会使用它们获得预期的行为。有关讨论,请参阅PEP-328。如果定义与基本(库存)模块同名的子包名称,则尤其如此。

答案 1 :(得分:0)

(1)是的,这是预期的行为。

(2)明确的相对导入是

from .module_a import ClassA

,而不是

from module_a import ClassA

可以是相对的也可以是绝对的,并且可以在顶级包和模块之间产生冲突。

(3)是的,这是相对进口的优势之一。主要好处可能是必须输入更少:)