从__init__中的Python子模块导入方法,但不是子模块本身

时间:2019-06-14 10:03:55

标签: python python-import python-module

我有一个具有以下结构的Python模块:

mymod/
    __init__.py
    tools.py
# __init__.py
from .tools import foo
# tools.py
def foo():
    return 42

现在,当import mymod时,我看到它具有以下成员:

mymod.foo()
mymod.tools.foo()

我不想要后者;它只会污染名称空间。

很有趣,如果将tools.py称为foo.py,您将得到想要的东西:

mymod.foo()

(显然,这仅在每个文件只有一个功能的情况下有效。)

如何避免导入tools?请注意,将foo()放入__init__.py是不可选择的。 (实际上,有foo之类的许多函数会使文件绝对混乱。)

3 个答案:

答案 0 :(得分:4)

object属性的存在对于维持导入系统的正常功能至关重要。 Python导入的常规不变式之一是,如果在from types import SimpleNamespace def dict2obj(data): """将字典对象转换为可访问的对象属性""" if not isinstance(data, dict): raise ValueError('data must be dict object.') def _d2o(d): _d = {} for key, item in d.items(): if isinstance(item, dict): _d[key] = _d2o(item) else: _d[key] = item return SimpleNamespace(**_d) return _d2o(data) 中注册了模块mymod.tools,则x.y模块具有一个指向{{1} }模块。否则类似

sys.modules

中断,甚至取决于Python版本

x

可能会中断。即使您不认为自己会做任何会破坏的事情,其他工具和模块也要依赖这些不变式,而尝试删除该属性会导致一系列兼容性问题,这些问题根本不值得。


试图使y不出现在x.y模块的命名空间中,就像是试图不使“私有”(前导下划线)属性出现在对象的命名空间中。这不是设计Python的工作方式,而试图强迫它以这种方式工作会导致更多问题,而不是解决的问题。

下划线前导约定不仅适用于实例变量。您可以在import x.y x.y.y_function() 模块上加上下划线,将其重命名为from x import y 。这样可以防止它被tools导入(除非您明确地将其放入mymod列表中),并且会更改IDE和linters处理直接访问它的尝试的方式。

答案 1 :(得分:0)

尝试将其放入您的__init__.py文件中:

from .tools import foo
del tools

答案 2 :(得分:0)

您不是要导入tools模块,而是可以像导入操作一样在导入软件包时使用它:

import mymod

您将有权访问__init__文件中定义的所有内容以及该软件包的所有模块:

import mymod

# Reference a module
mymod.tools

# Reference a member of a module
mymod.tools.foo

# And any other modules from this package
mymod.tools.subtools.func

foo内导入__init__时,就是在foo那里可用,就像在其中定义了一样,但是当然您是在tools中定义的这是一种整理软件包的方法,因此,既然您将其导入__init__内,就可以:

import mymod

mymod.foo()

或者您也可以单独导入foo

from mymod import foo

foo()

但是您可以导入foo而不在__init__中使用它,您可以执行与上面的示例完全相同的以下操作:

from mymod.tools import foo

foo()

您可以使用两种方法,两种方法都是正确的,在所有这些示例中,您都不会“使文件杂乱无章”,因为您可以看到使用foo访问mymod.tools.foo是命名空间,因此您可以使用多种方法在其他模块中定义了foo个。