Python导入机制

Python导入机制,python,coding-style,import,module,conventions,Python,Coding Style,Import,Module,Conventions,我有两个相关的Python“导入”问题。它们很容易测试,但我希望答案是语言定义的,而不是特定于实现的,而且我也对样式/约定感兴趣,所以我在这里问 (一) 如果模块A导入模块B,模块B导入模块C,那么模块A中的代码是否可以在没有显式导入的情况下引用模块C?如果是这样的话,我认为这是错误的做法,对吗 (二) 如果我导入模块A.B.C,是否也导入模块A和A.B?如果是这样的话,按照惯例是否最好显式地导入A;进口A.B;导入A.B.C?您应该知道的第一件事是Python语言不是ISO标准。这与C/C++

我有两个相关的Python“导入”问题。它们很容易测试,但我希望答案是语言定义的,而不是特定于实现的,而且我也对样式/约定感兴趣,所以我在这里问

(一)

如果模块A导入模块B,模块B导入模块C,那么模块A中的代码是否可以在没有显式导入的情况下引用模块C?如果是这样的话,我认为这是错误的做法,对吗

(二)


如果我导入模块A.B.C,是否也导入模块A和A.B?如果是这样的话,按照惯例是否最好显式地
导入A;进口A.B;导入A.B.C

您应该知道的第一件事是Python语言不是ISO标准。这与C/C++有很大的不同,这意味着没有“正确”的方法来定义语言行为——CPython可能只是因为它是这样编码的,而Jython可能会反过来做

关于您的问题,请记住,“导入”模块是一个由两部分组成的操作:首先加载模块-如果从未加载过,例如,如果sys.modules中没有该模块,则在本地命名空间中将名称绑定到该模块

因此:

1) 是的,您可以通过提供适当的名称空间来引用模块a中的任何内容,例如,您必须执行以下操作

B.C.name=“某物”

我认为在Python程序中很少这样做,这可能被认为是不好的做法,因为它强制执行“可传递的dep”-如果某个模块B实现被重构并且不再依赖C,它应该继续提供C模块只是为了满足dep

当然,设置“全部”可以防止这种情况发生,一个好的做法可能是将“全部”放在所有模块中,然后只导出您希望真正公开的符号

2) 是和否,做什么

import a.b.c.d 
在所有模块上执行第一个导入阶段(加载),但第二个阶段仅在a上执行(递归地,在b中执行c等),但链中的所有模块必须由完整命名空间引用;在这样的导入之后,您可以

a.something
a.b.something
a.b.c.something
但你做不到

c.something
b.something
我必须承认,这种用法也很少见;我通常更喜欢“从模块导入某物”的方式进行导入,通常您只需要请求所需的内容—这种嵌套在库中并不常见,其用法也不常见

很多时候都有“外部包”,只是用于组织,其中包含带有类的模块。上面的a、b、c很可能只是包,而d是一个真正包含类、函数和其他对象的模块。因此,正确的用法是:

from a.b.c.d import name1, name2, name3

我希望这能满足你的好奇心。

艾伦给出了一个很好的答案,但我想补充一点,对于你的问题1,这取决于你所说的“进口”是什么意思

如果使用
fromcimport x
语法,则
x
将在
B
的命名空间中可用。如果在
A
中执行
导入B
,您将可以从
A
B.x
的身份访问
x


与其说这是一种不好的做法,还不如说是一种潜在的混淆,并且会使调试等变得更加困难,因为您不一定知道对象来自何处。

“语言定义的,而不是特定于实现的”您是说Python实现在某种程度上是不同的吗?您意识到了哪些具体差异?好吧,没有。也许没有什么区别,但是规范中没有定义的东西取决于实现。Python文档中充斥着关于CPython实现细节的警告,这些可能不适用于其他实现。感谢您提供详细的答案!虽然不是ISO,但有一个Python语言参考定义了“适当”的行为,包括导入:语言参考指出了CPython实现的细节,但旨在成为该语言的通用规范,因此它不完全依赖于实现。这是一个有用的澄清,谢谢。我一直认为,
import
类似于Java风格的包导入,但很明显,这种相似性只是表面的。如果它令人困惑,这难道不足以称之为坏习惯吗?仅仅从IMHO读取代码就可以看出代码的作用。