python import package - 子包不应该出现在符号表中

rok*_*ngh 7 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'
Run Code Online (Sandbox Code Playgroud)

顶级__init__.py看起来像这样:

#!/usr/bin/env python

from Source.WildMod import WildFunc
Run Code Online (Sandbox Code Playgroud)

并且,为了完整起见,下级__init__.py看起来像这样:

#!/usr/bin/env python

__all__ = ["WildMod"]
Run Code Online (Sandbox Code Playgroud)

好的,现在我打开解释器,导入模块,然后查看符号:

>>> import PyModTest
>>> dir(PyModTest)
['Source', 'WildFunc', '__builtins__', '__doc__', '__file__', '__name__', '__package__', '__path__']
Run Code Online (Sandbox Code Playgroud)

看,"源"模块出现了,即使我从未专门导入它!

我想看到的唯一符号(除了私有符号)是我的'WildFunc'.有没有办法隐藏'Source'包?

Dav*_*d Z 7

这里有两点需要注意:

  • 在Python中,模块是实际对象,其名称之间出现的点表示实际的属性访问
  • 你正在做一个相对导入,这意味着Source实际上PyModTest.Source(感谢TokenMacGuy指出这一点)

所以:为了导入PyModTest.Source.WildMod.WildFunc,Python必须这样做

  1. 导入PyModTest(已经由您完成)
  2. 检查并查看是否有一个名为Source,如果没有,则通过从中导入属性来创建该属性PyModTest/Source/__init__.py
  3. 检查并查看是否有一个被调用的属性WildMod,如果没有,则通过从中导入来创建属性PyModTest/Source/WildMod.py
  4. 检查并查看是否有一个名为的属性WildFunc(它有)

PEP 302Python语言参考中讨论了一些相关的细节.

更深入的机制,点名称导入由其组件分开.对于" import spam.ham",首先执行" import spam",并且仅当成功时" ham"作为" "的子模块导入spam.

如果您不希望命名变量Source,那么很容易修复:del Source在导入函数之后.但请记住,它将阻止以后运行的任何代码访问PyModTest.Source.<anything>(除非WildFunc,因为您已保存对该引用的引用).我肯定会建议忽略引用Source,而不是删除它,因为它不会伤害任何东西.

  • `Source`是`PyModTest`的子包,隐式导入被静默转换为`来自PyModTest.Source import ...`,所以必须添加`Source`模块作为`PyModTest`模块的属性.如果在`PyModTest`包之外找到`Source`(不太可能,子包优先于`sys.path`),则不会发生这种情况.为避免让自己和他人混淆,总是喜欢绝对进口. (2认同)