我有一个具有以下结构的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
之类的许多函数会使文件绝对混乱。)
答案 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
个。