如何将子模块名称保留在Python包的名称空间之外?
我想要某个模块的接口包含一定数量的函数和类(而不是其他)。我可以在一个文件中实现所有这些,并且很容易获得我想要的接口。但是,由于有大量的代码,我宁愿分裂了整个事情分成几个文件,说如何将子模块名称保留在Python包的名称空间之外?
mypackage/
__init__.py
a.py
b.py
c.py
d.py
如果想获得理想的界面,我定义一个__init__.py
文件为导入所有公共包从a
,b
,c
和d
符号:
from a import func_a1, func_a2, ClassA1, ClassA2
from b import func_b1, func_b2, ClassB1, ClassB2
from c import func_c1, func_c2, ClassC1, ClassC2
from d import func_d1, func_d2, ClassD1, ClassD2
如果我导入使用
import mypackage
包
包名称空间还包含符号a
,b
,c
和d
。这些名称是实现细节,不属于我的界面。我不希望它们显示为“公共”符号。什么是摆脱他们的最佳方式?
我考虑的选择是
使用一个单独的模块,而不是包装。界面看起来很好,但是实现会比现在更清晰。
-
行
del a, b, c, d
加入的
__init__.py
末。工作正常,但看起来像一个黑客。 (例如,你不能import __init__
更多,如果没有此项线路正常。) 重命名
a
,b
,c
和d
到_a
,_b
,_c
和_d
。现在它们被包含在mypackage
的命名空间中作为“私有”符号,我很好,但它感觉有点奇怪,我的文件名以开头, )。
有什么更好的建议吗?或者想要选择哪个选项?
或者我只是为了肛门,不应该关心整个事情?
如果你真的要删除从命名空间中的名字,那么你可以只使用他们的del
声明,他们会消失,像风。
从http://docs.python.org/tutorial/modules.html:
import语句使用 以下约定:如果一个包的 __init__.py代码定义了一个名为列表__all__,它被认为是应导入模块的名称列表 当从包导入*时遇到 。
在你mypackage/__init__.py
,尝试添加此:
# add this line, replace "..." with the rest of the definitions
# you want made public
__all__ = ['func_a1', 'func_a2', 'ClassA1', 'ClassA2', ...]
from a import func_a1, func_a2, ClassA1, ClassA2
from b import func_b1, func_b2, ClassB1, ClassB2
from c import func_c1, func_c2, ClassC1, ClassC2
from d import func_d1, func_d2, ClassD1, ClassD2
但是,这不会直接访问它时影响名称空间的内容。 – 2011-03-10 20:40:15
Gah,我误解了你的问题......如果你正在从'mypackage import *'执行操作,我认为你是这样的。在这种情况下,它似乎不起作用,即使你在你的模块中定义了'__all__',''''''''''' – dcrosta 2011-03-10 20:41:54
这是一个被单一的Javascript功能模块启发的解决方案:
def __init__module():
from os import path
def _module_export_1():
return path.abspath('../foo')
def _module_export_2():
return path.relpath('foo/bar', 'foo')
g = globals()
g['module_export_1'] = _module_export_1
g['module_export_2'] = _module_export_2
__init__module()
虽然模块需要进口从OS“路径”,“路径”不污染模块命名空间。模块名称空间中唯一的残留是__init_module(),它明显由双下划线前缀标记为私有。
另一种选择是在每个功能的顶部导入所需的模块,而不是模块的顶部。第一次导入模块后,后续导入只是sys.modules字典中的查找。
但我同意其他评论者的意见 - Python约定不担心模块名称空间污染,只是让模块的用户明白哪些部分名称空间是公共API,哪些是内部的。
不幸的是,这种方法不起作用。正如你在我的文章中所看到的,我从来没有将名称'a'导入到包的名称空间中 - 我只是从'import func_a1,...'中使用''。如果我在普通模块中这样做,只会在模块的名称空间中显示名称'func_a1,..'。但是由于'a'是一个包的子模块,它的名称'a'被插入到包的名称空间中。如果我从一个函数中导入所有东西,会发生同样的事情。 – 2011-04-04 18:46:08
如果包中的某些文件确实是实现细节,请继续并在它们前面加上下划线 - 这就是我们使用它们的原因。
例如,如果你在看你会看到
__init__.py
==================================================
"""create and manipulate C data types in Python"""
import os as _os, sys as _sys
__version__ = "1.1.0"
from _ctypes import Union, Structure, Array
from _ctypes import _Pointer
from _ctypes import CFuncPtr as _CFuncPtr
...
正如你可以看到,即使os
和sys
成了该文件的实施细则。
不妨去喝苏打水。也就是说,除了你以外,没有人真正关心包的命名空间中的内容。 – 2011-03-10 20:29:24
@Ignacio:可能你是对的:)例如在交互式使用中,当不需要的名称会干扰标签扩展时,它会让我感到恼火。 – 2011-03-10 20:37:21
这只是我的看法,但是'import __init__'在选项2中似乎更加骇人听闻,所有事情都考虑到了。 – JAB 2012-06-07 15:09:20