我有两个相关的Python'导入'问题。它们很容易测试,但我想要语言定义的答案,而不是特定于实现的答案,我也对样式/惯例感兴趣,所以我在这里问。
1)
如果模块A导入模块B,而模块B导入模块C,是否可以在模块A参考模块C中编码而无需显式导入?如果是这样,我认为这是不好的做法我是否正确?
2)
如果我导入模块A.B.C,是否也导入模块A和A.B?如果是这样,按照惯例更明确地import A; import A.B; import A.B.C
?
答案 0 :(得分:12)
您应该知道的第一件事是Python语言不是ISO标准。这与C / C ++有很大不同,它意味着没有“正确”的方式来定义语言行为--CPython可能只是因为它是以这种方式编码而做的,而Jython可能会反过来。
关于你的问题,记住“导入”模块是一个由两部分组成的操作:首先加载模块 - 如果它从未被加载过,例如如果它在sys.modules中不可用,那么名称将绑定到本地名称空间中的该模块。
因此:
1)是的,您可以通过提供适当的命名空间来引用模块a中的任何内容,例如:你必须做类似
的事情B.C.name =“something”
我认为这在Python程序中很少用,并且可能被认为是不好的做法,因为它强制“传递dep” - 如果某个模块B实现被重构并且不再依赖于C,它应该继续提供C模块只是为了满足A deps。
当然设置__ all __可以防止这种情况,一个好的做法可能是将__ all __放在所有模块中,然后导出 你想要真正公开的符号。
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 :(得分:11)
Alan给出了一个很好的答案,但我想补充一点,问题1取决于你对“进口”的意思。
如果您使用from C import x
语法,则x
的命名空间中将显示B
。如果您在A
中import B
,则 将x
A
作为B.x
访问{/ 1}}。
这并不是一个可能令人困惑的糟糕做法,并且会使调试等变得更难,因为你不一定知道对象来自哪里。