2

我正在用 Python 编写一个具有以下模块结构的小包

package/
  __init__.py
  cls1.py
  cls2.py
  cls3.py
  mod1.py
  mod2.py

其中每个clsN.py都有一个类ClsN,并且每个都modN.py包含使用这些类的各种功能。我希望我的导入结构看起来像

package
package.Cls1
package.Cls2
package.Cls3
package.mod1
package.mod1.func1
...
package.mod2
package.mod2.func2
...

不污染命名空间。现在我遇到的问题是我可以通过package.Cls1and访问这些类中的任何一个package.cls1.Cls1,并且我还可以访问在package/cls1.py(包括导入)中定义的所有内容。我试过设置__all__变量,但除了在from package import *. 有没有办法让 Python 不显示clsN为子模块?甚至只是一种在这些文件中隐藏导入的方法?我不希望我图书馆的用户有两种进入每个班级的方式。

4

2 回答 2

4

标准库有两种处理这种情况的方法。

第一个很简单:只需将私有模块标记为私有,就像将任何其他属性标记为私有一样:使用下划线前缀。这并没有对用户隐藏它们,但它确实表明用户不应该使用它们(并且可能会阻止 iPython 或 PyDev 之类的东西将它们作为完成提供),这通常已经足够了。

唯一真正的问题是模块名称上的下划线前缀也倾向于暗示它们是本机加速器 - 换句话说,用户可能期望_foofoomodule.c而不是实现_foo.py

另一种选择是要么不导入它们 - 使用from submodule import name, other, yetanother-要么del在模块末尾导入它们。您明确希望package.Cls1与 , 等类型相同的事实package.cls1.Cls1意味着这正是您想要的。

如果需要,用户仍然可以显式导入它们。但是 Python 通常不会给你任何阻止恶意或故意愚蠢的方法,你不应该尝试。

于 2013-07-09T19:35:16.967 回答
2

首先,我建议不要太担心从哪里可以看到什么。如果用户尝试访问package.mod1.Cls1,如果它有效,真的有问题吗?Python 通常是一种相当宽松的语言,试图隐藏东西往往比它的价值更麻烦。

也就是说,如果您想减少非标准访问的可能性,一个好方法是将您的类导入具有替代名称的模块中,以下划线开头。名称开头带有单下划线的变量不会被导入,from _ import *也不会出现在dir列表中。您可以这样做:

mod1.py

from .Cls1 import Cls1 as _Cls1
from .Cls2 import Cls2 as _Cls2
from .Cls3 import Cls3 as _Cls3

然后只需在模块代码中使用下划线名称。其他想要获取课程的代码可能会在他们的“官方”位置找到它们。

于 2013-07-09T19:30:13.130 回答