Python 导入、路径、目录与模块
首先,我想说的是,我在过去一周做了很多研究,但还没有找到这些问题的实际答案——只是一些模糊的回答,根本没有解释清楚发生了什么。如果我只是错过了我想要的信息,我很抱歉——请直接告诉我正确的方向。
我的目录结构是:
TestProject/
runtest*
testpackage/
__init__.py
testmod.py
testmod2.py
testsubs/
testsubmod.py
几点说明:
- 我在Ubuntu上使用python2.7
- 我在用bpython进行测试
- 我从特定目录运行bpython,以测试导入的行为
- 我试图遵循最佳实践。
- 这个包没有安装,它在一个随机的开发目录里
- 这个目录不在pythonpath中
- 在包目录中有一个init.py文件
- 嵌套目录中没有init.py文件
- 这个init.py文件是空的
- testpackage/testmod.py包含TestModClass
- testpackage/testsubs/testsubmod.py包含TestSubModClass
我观察到的事情:
- 当我从TestProject/运行bpython时,import testpackage可以正常工作
- 这并没有导入testpackage.testmod
- 我根本无法访问testpackage.testmod
- 当我从TestProject/运行bpython时,import testpackage.testmod失败了
- 当我从TestProject/运行bpython时,from testpackage import testmod可以正常工作
- 我可以在init.py中添加代码来明确导入testmod.py,但无法导入testsubs/testmod.py
- 我觉得这样做不太对,如果用户不想导入那个模块怎么办?
- 从testmod.py我可以导入testmod2,但不能导入testpackage.testmod2
- 这样做会很好,这样我就可以用与标准库或twisted重名的模块命名(比如testpackage.logging),而不会导致错误(我不想把自己的模块命名成customerlogging,而不是直接用mypackage.logging)
然后是我的问题:
- Python在处理位于pythonpath中的包和模块的导入时,和从当前目录导入时有什么不同吗?
- 为什么import testpackage不能让我访问testpackage.testmod?当我导入os时,我可以访问os.path(等等)。
- 对于一个包,我应该在基础目录中只使用一个init.py,还是应该在后续目录中嵌套它们?
- 我如何指定包名来导入模块?例如,从testmod.py,我想导入testpackage.testmod2,而不是仅仅导入testmod2。
- 从子目录导入子模块的正确方法是什么?
- 我看到的唯一解决方案是从init.py将那个目录添加到pythonpath中,但我不知道这是否是正确的方法。
提前感谢你的帮助。
2 个回答
- 不可以。当前目录只是被添加到了 PYTHONPATH 中。
- 首先,你需要在里面放一个 __init__.py 文件。其次,os.path 是因为 os 在导入 os.path。
- 你需要在每个目录里都有一个 __init__.py 文件,包括包含
testpackage
目录的那个目录。 - 在这个包的 __init__.py 文件中,导入你想要提供的模块。
- 从 sub1.sub2 导入 submodule
- 不,如果最上层的目录在 PYTHONPATH 中,并且这个目录和子目录都有它们的 __init__.py 文件,那么你只需要这样就可以从任何子目录导入。
首先,你可以在Python教程的第6节找到你需要的所有信息。
(1) Python在导入位于pythonpath中的包和模块时,和从当前目录导入时处理方式有区别吗?
没有区别。实际上,Python在导入模块时总是会查找sys.path
。当前目录的模块之所以能被找到,是因为sys.path
中有一个空字符串的条目,表示当前目录。
(2) 为什么
import testpackage
不能让我访问testpackage.testmod
?我导入os
后可以访问os.path
(等等)。
为了提高效率,import testpackage
只会加载testpackage/__init__.py
。如果你需要testpackage.testmod
,你必须明确地导入它:
import testpackage # Just imports testpackage, not testpackage.testmod!
import testpackage.testmod # Import *both* testpackage and testpackage.testmod!
如果你总是想导出testmod
,可以在__init__.py
中导入它,这就是os
(os/__init__.py
)所做的。这样,如果你导入testpackage
,testpackage.testmod
就会自动可用。
由于Python是跨平台的,实际上没有办法一致且自动地加载目录中的模块,因为某些文件系统是不区分大小写的(比如Windows!)。Python无法判断是加载os/path.py
作为os.path
还是os.Path
,等等。
(3) 在一个包中,我应该只在基础目录使用一个
__init__.py
,还是应该在后续目录中嵌套它们?
每个子包都需要一个__init__.py
。曾经讨论过是否可以去掉这个要求,但最终决定保留它。
(4) 我该如何指定包名来导入模块?也就是说,从
testmod.py
中,我想导入testpackage.testmod2
而不是仅仅testmod2
。
这样做应该可以。只要确保你从顶层目录运行代码。如果当前目录是testpackage
,testmod
就不知道它在一个包里。
不过,推荐的方式是使用相对的包内导入:
from . import testmod2
这样可以避免名称冲突,如果有一个全局模块叫testmod2
,你可以在你的包中使用知名模块的名称而不会出现问题。
(5) 从子子目录导入子模块的正确方法是什么?我看到的唯一解决方案是从
__init__.py
中将该目录添加到pythonpath,但我不知道这是否正确。
不,千万不要这样做!绝对不要在一个父目录已经在sys.path
中的情况下,把一个目录添加到sys.path
!这样可能会导致你的模块被加载两次,这是个坏事!
通常,你应该能够使用绝对或相对导入从子包中加载模块:
import testpackage.testsubs.testsubmod
from testpackage.testsubs import testsubmod
from .testsubs import testsubmod
只要确保在testsubs/
中创建一个__init__.py
!