我的PYTHONPATH中有一个看起来像这样的包:
package/
__init__.py
module.py
print 'Loading module'
如果我从package/
目录运行Python(或在此目录中编写另一个模块)并输入
import module
它加载module.py并按预期打印出“加载模块”。但是,如果我输入
from package import module
它加载module.py并再次打印“加载模块” ,这是我不希望的。这是什么理由?
注意:我认为我从技术上理解为什么Python会这样做,因为import module
的sys.modules键只是"module"
,但对于from package import module
它是"package.module"
。所以我想我想知道的是为什么密钥在这里是不同的 - 为什么不将文件的路径名用作密钥,以便Python做到人们期望的呢?
答案 0 :(得分:2)
实际上,通过运行package
目录中的代码,您错误配置了Python。您不应该将该目录放在sys.path
上,因为它位于包中。
Python不使用文件名作为密钥,因为它不导入文件,而是导入模块。允许人们做'import c:\jim\my files\projects\code\stuff
'会鼓励各种各样的肮脏。
请考虑这种情况:如果您在~/foo/package/
和~/bar
处于PYTHONPATH
状态,该怎么办? - 〜/ bar只是~/foo
的符号链接?你希望Python解决,然后为你重复删除符号链接?如果将相对目录放在PYTHONPATH上,然后更改目录怎么办?如果'foo.py'是'bar.py'的符号链接怎么办?你是否期望这两者都被重复删除?如果他们不是符号链接,但只是精确的副本怎么办?添加复杂的规则以尝试在模糊的环境中做一些方便的事情意味着它为其他人做了一些非常不方便的事情。 (Python zen 12:面对模棱两可,拒绝猜测的诱惑。)
Python在这里做了一些简单的事情,你有责任确保环境设置正确。现在,您可能会认为默认情况下将当前目录放在PYTHONPATH
上并不是一个好主意 - 我甚至可能同意您的意见 - 但鉴于它存在,它应遵循相同的一致规则集其他路径条目。如果要从任意目录运行,您的应用程序始终可以从sys.path
开始从sys.path.remove('')
删除当前目录。
答案 1 :(得分:2)
这是当前模块系统的一个小缺陷。
导入模块时,可以从当前名称空间执行此操作,该名称空间没有名称。此命名空间中的值与 package 中的值相同,但解释器无法知道它。
导入 package.module 时,从包命名空间导入模块。
这就是为什么main.py应该在包forlder之外。 许多模块都有这个组织:
package /
main.py
package /
sub_package1/
sub_package2/
sub_package3/
module1.py
module2.py
仅调用main.py以确保正确设置名称空间,即当前名称空间是main.py的。它无法在module2.py中调用 import module1.py 。你需要调用 import package.module1 。使事情变得更简单和均匀。
是的,导入当前文件夹作为当前无名文件夹是一个坏主意。 如果你超越一些脚本,那就是PITA。但是当Python从那里开始时,它并非毫无意义。