python 导入包 - 子包不应出现在符号表中
我想知道为什么在导入一个Python包时,包含子模块的目录(子包)会作为一个符号出现。比如说,如果我有这样一个包:
PyModTest/ Top-level package
__init__.py Initialize the package
Source/ Subpackage holding source files
__init__.py
WildMod.py Submodule containing a function: 'WildFunc'
这个包的顶层 __init__.py 文件看起来是这样的:
#!/usr/bin/env python
from Source.WildMod import WildFunc
为了完整起见,底层的 __init__.py 文件是这样的:
#!/usr/bin/env python
__all__ = ["WildMod"]
好吧,现在我打开解释器,导入这个模块,然后查看符号:
>>> import PyModTest
>>> dir(PyModTest)
['Source', 'WildFunc', '__builtins__', '__doc__', '__file__', '__name__', '__package__', '__path__']
你看,'Source' 模块出现了,尽管我并没有特别导入它!
我只想看到一个符号(除了私有的那些),就是我的 'WildFunc'。有没有办法隐藏 'Source' 包呢?
1 个回答
8
这里有两点需要注意:
- 在Python中,模块实际上是对象,模块名之间的点(.)表示访问一个属性。
- 你正在做的是相对导入,这意味着
Source
实际上是PyModTest.Source
(感谢TokenMacGuy指出这一点)。
所以:为了导入PyModTest.Source.WildMod.WildFunc
,Python需要:
- 导入
PyModTest
(这一步你已经做过了)。 - 检查是否有一个叫
Source
的属性,如果没有,就从PyModTest/Source/__init__.py
导入来创建这个属性。 - 检查
Source
是否有一个叫WildMod
的属性,如果没有,就从PyModTest/Source/WildMod.py
导入来创建这个属性。 - 检查
WildMod
是否有一个叫WildFunc
的属性(它是有的)。
一些相关的细节可以在PEP 302和Python语言参考中找到。
在机制的更深层次,带点的名称导入会被分解成它的组成部分。对于"
import spam.ham
",首先会执行"import spam
",只有在这一步成功后,才会将"ham
"作为"spam
"的子模块导入。
如果你不想有一个叫Source
的变量,这很简单:在导入函数后只需del Source
。但要记住,这样会阻止后续运行的代码访问PyModTest.Source.<任何东西>
(除了WildFunc
,因为你已经保存了对它的引用)。我建议你只是忽略对Source
的引用,而不是删除它,因为它并没有造成什么问题。