【问题标题】:How to import a module without sub-imports如何在没有子导入的情况下导入模块
【发布时间】:2026-01-05 22:55:01
【问题描述】:

我正在构建一个模块,但我很难理解哪个是避免工作空间污染的最佳实践。

示例代码

我的模块是:

aModule\
    __init__.py
    aSubModule.py
    someFunctions.py

文件内容为:

初始化.py

from .someFunctions import function1, function2
from aModule import aSubModule

someFunctions.py

from numpy import exp,log,sqrt

def function1():
    print('function1: Hello World!')
    
def function2():
    print('function2: Hello ' + aUtilityFunction())
    
def aUtilityFunction(): #This should not be imported
    return 'World!'

aSubModule.py

from numpy import exp,log,sqrt

def function3():
    print('I am function 3')
    
def function4():
    print('I am function 4')

问题

什么时候做

import aModule

我希望能够访问

aModule.function1()
aModule.function2()
aModule.aSubModule.function3()
aModule.aSubModule.function4()

但是我也有以下不良行为:

问题 1

someFunctions.py 文件作为子模块导入。换句话说,我可以从 aModule.function1 和 aModule.someFunctions.function1 访问 function1 。在我看来,这很混乱。 我找到的唯一解决方案是重命名文件 _someFunctions.py 。前导下划线现在告诉 Python 不要导入它。这看起来不错,但我不确定这是否被认为是好的做法。

问题 2

函数 exp、log 和 sqrt 被导入到 aModule.aSubModule 下。我想访问 aSubModule 中的函数

aModule.aSubModule.function3()

但我想避免在 aModule.aSubModule 中使用 exp、log 和 sqrt

这是因为在我正在处理的“真实”子模块中,我只有 3-4 个与用户相关的函数,但超过 10-15 个导入。因此,当我尝试制表符完成时

aModule.aSubModule.<tab>

弹出大约 20 个条目,其中只有 3-4 个是相关的。

【问题讨论】:

  • 您可以在函数前加上下划线 (_) 以将其隐藏在帮助和自动完成中。还不够吗?
  • 所以我应该将 numpy 导入为 _np,将 pandas 导入为 _pd 并将我的文件命名为 _someFunction ?我认为这可行,但我试图打开其他人制作的一些模块,看看他们是如何做到的,但从未见过这种技术。这是好的做法吗?
  • 不确定,但我认为您想要的是 from module import * 语法,它只导入模块的 __all__ 特殊变量中明确列出的符号。更多细节在official doc.
  • 不幸的是,__all__ 特殊变量不会影响我帖子中描述的行为。我不想使用import * 语法,只是在导入父模块时避免导入子模块

标签: python python-3.x python-import python-module


【解决方案1】:

我找不到一个好的方法,但黑客是可能的。诀窍是任何以下划线开头的标识符都不会被帮助系统使用,而不是用于 tab 自动补全,即使它是一个模块标识符。所以为了避免自动访问不必要的标识符,你可以拥有包含 private 模块的包

aModule\
    __init__.py
    _someFunctions.py
    aSubModule\
        __init__.py
        _aSubModule.py

aModule __init__.py的内容:

from ._subFunctions import f1, f2
from . import aSubModule

aSubModule __init__.py的内容:

from ._aSubModule import f3, f4

我必须承认它相当 hacky 并且不是 Pythonic。也许自定义导入器会带来更简洁的代码,但我无法通过 importlib 模块找到自己的方式。

我的结论是,Pythonic 的方式可能不是试图隐藏通过模块导入的名称,而只是在当前命名空间中导入你需要的名称。

【讨论】:

    最近更新 更多