Google Python 风格指南和相关导入

Google Python Style Guide & relative imports

Google Python 风格指南 says:

Do not use relative names in imports. Even if the module is in the same package, use the full package name. This helps prevent unintentionally importing a package twice.

导致两次导入包的示例设置是什么?

这是对 隐式相对导入 的 Python 2 行为 (deprecated since 2.6) 的引用:允许 import bar 在一个包 foo 来引用模块 foo.bar。考虑 sys.path 上的一个目录,它看起来像

…
|-- client.py
`-- pkg
    |-- __init__.py
    |-- mod.py
    `-- script.py

具有以下内容的文件:

client.py

print "client..."
from pkg import mod,script
print "client!"

pkg/__init__.py

print "pkg"

pkg/mod.py

print "mod: %r"%__name__

pkg/script.py

print "script:",__name__,__package__

if __name__=='__main__':
  import mod,client
  print "script!"

在此设置中 mod 可以轻松导入两次:

$ PYTHONPATH=… python …/pkg/script.py
script: __main__ None
mod: 'mod'
client...
pkg
mod: 'pkg.mod'
script: pkg.script None
client!
script!

为了减少配置开销,Python 将目录 pkg 添加到 sys.path,有效地假定 script.py 是顶级模块 script.不幸的是,这意味着 import mod 创建了一个名为 mod 顶级 模块,而 pkg.mod 的显式导入稍后会导致它的另一个副本以其全名存在(仅在导入 pkg 本身之后)。

recognized that this poses a problem, and later -m was adjusted 告诉正在执行的模块关于在其中找到它的包,以便相对导入(隐式或显式)正常工作:

$ PYTHONPATH=… python -m pkg.script
pkg
script: __main__ pkg
mod: 'pkg.mod'
client...
script: pkg.script None
client!
script!

请注意,pkg 现在首先导入(由 -m 本身!),script 现在立即具有 __package__ 属性,并且 mod 只导入一次。当然, script 本身 被(仍然)加载了两次,因为它的名字第一次被 __main__ 替换,所以 from pkg import script 可以在下面找到它一个不同的名字。

道德 是,根据 __name__=='__main__' 实现“模块也可以是脚本”从根本上被打破了(和替换 have been rejected):一个模块已经 一个 __name__,并且创建一个单独的模块对象作为入口点以便它的 __name__ 可以不同就像复制 Java class(及其所有静态数据)提供 main。制作一个没有人导入的模块有效,但却是矛盾的(并且破坏了导入包的所有成员的代码检查)。