谷歌Python风格指南说:
在导入中不要使用相对名称。即使模块在同一个包中,也要使用完整的包名称。这有助于防止无意中导入包两次。
导入两次包的示例设置是什么?
这是对隐式相对导入的Python 2行为(自2.6以来已弃用(的引用:允许包foo
中模块中的import bar
引用模块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
本身之后(。
人们认识到这会带来一个问题,后来-m
被调整为告诉正在执行的模块关于它所在的包的信息,以便相对导入(隐式或显式(正常工作:
$ 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__'
而言,它从根本上被破坏了(替换被拒绝(:一个已经的模块有的__name__
,创建一个单独的模块对象作为入口点,使其__name__
可以不同,这与复制提供main
的Java类(及其所有静态数据(一样荒谬。制作一个从来没有人导入过的模块是可行的,但它是矛盾的(并破坏了导入包的所有成员的代码检查(。