Python 中意外的相对导入行为

发布于 2024-11-05 02:53:18 字数 1647 浏览 3 评论 0原文

今天我遇到了一种非常令人惊讶的相对导入行为(不幸的是,在我拔掉头发近 4 个小时之后)。

我一直有这样的印象:如果您在名为“package”的包中的模块名称“module_a.py”内有“Class A”,您可以等效地使用:

from package.module_a import ClassA

或者

from module_a import ClassA

只要您从其中的模块导入“包裹”。我认为这是相对重要的。

我从来没有遇到过问题,直到今天,当我需要根据 A 类检查对象的实例时,我惊讶地发现了一个非常不寻常的行为。

考虑以下内容:

package/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)

package/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. 我总是认为,当子包结构可能移动时,相对导入在大型重构中提供了额外的便利。这是相对导入的主要好处吗?

I ran into a very surprising relative import behavior today (unfortantely after nearly 4 hours of pulling my hair out).

I have always been under the impression that if you have "Class A" inside of a module name "module_a.py" within a package named "package" that you could equivalently use either:

from package.module_a import ClassA

or

from module_a import ClassA

as long as you were importing from a module within "package". I understood this to be a relative import.

I never had a problem until today when I needed to check the instance of an object against Class A and I was surprised to find a very unusual behavior.

Consider the following:

package/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)

package/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)

Now when executing module_b.py you get:

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

I have followed the logic and now see why this occurs - it was not real obvious as I assumed that the binding for ClassA was the same regardless of an absolute or relative import. This caused a very nasty bug for me that was very hard to isolate.

My questions:

  1. Is this the behavior that would be expected?

  2. If this is the logical way that it should work - it is then not clear to me why I would use relative imports if they are not compatible (in the above sense) with absolute imports. Is there a good explanation here that I am missing?

  3. I always assume that relative imports provided additional ease in large refactors when sub package structure might be moved around. Is this the main benefit of a relative import?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

痴者 2024-11-12 02:53:18

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

Since implicit relative imports have caused problems they have been removed in Python 3. You often don't get expected behavior with them. See PEP-328 for a discussion. This is especially true if you define a subpackage name with the same name as a base (stock) module.

隐诗 2024-11-12 02:53:18

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

(2) 显式相对导入 is

from .module_a import ClassA

和 not ,

from module_a import ClassA

它可以是相对的也可以是绝对的,并且可能会导致顶级包和模块之间发生冲突。

(3)是的,这是相对进口的优势之一。主要的好处可能是减少打字:)

(1) Yes, this is expected behaviour.

(2) An explicit relative import is

from .module_a import ClassA

, and not

from module_a import ClassA

which can be relative as well as absolute, and which can give conflicts between top-level packages and modules.

(3) Yes, that is one of the advantages of relative import. The main benefit is probably having to type less :)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文