Python:包中的"私有"模块

Fre*_*ool 38 python python-module

我有一个封装mypack与模块mod_a,并mod_b在里面.我打算包装本身并mod_a自由进口:

import mypack
import mypack.mod_a
Run Code Online (Sandbox Code Playgroud)

但是,我想保留mod_b专属用途mypack.那是因为它的存在仅仅是为了组织后者的内部代码.

我的第一个问题是,在Python编程中接受这样的"私有"模块是否可以接受?

如果是,我的第二个问题是,向客户传达这一意图的最佳方式是什么?我是否在名称前加下划线(即_mod_b)?或者声明一个子包private并将所有这些模块放在那里是一个好主意吗?

Jer*_*emy 37

我使用下划线为私有模块添加前缀,以将意图传达给用户.在你的情况下,这将是mypack._mod_b

这与PEP8的建议完全相同(但并不完全类似),当C-extension模块被Python模块包装时,它将C-extension模块命名为前导下划线; 即_socketsocket.

  • 实际上,[PEP8](https://www.python.org/dev/peps/pep-0008/?#public-and-internal-interfaces)说:`即使适当地设置了__all__,内部接口(包,模块,类也是如此) ,函数,属性或其他名称)仍应以单个下划线作为前缀。 (2认同)

Fre*_*ool 14

我已经解决的解决方案是创建一个子包'private'并将我希望隐藏的所有模块放在那里.通过这种方式,它们可以保存起来,使mypack模块列表更清晰,更易于解析.

对我来说,这看起来也不是单调的.

  • 如果我看到“private”作为模块名称,我会想知道包里有什么。我不想通读内容才能弄清楚为什么如此组织。模块和包名称应指示其中的内容,而不是其私有或公共状态 (5认同)
  • 感谢您的更新,并首先建议这种方法.我在"私有"子包名称前加上'z_',因此它在IDE代码完成下拉列表中显示为最后一个.我在子包的`__init __.py`中使用相对导入来仅公开"public"函数.在PyCharm和Jupyter中,为了保持内部模块的名称没有下拉,每个模块必须有一个与模块同名的函数,我必须在`__init __.py`中导入函数.你可能已经知道了这一切,但如果不是这样的话.如果您希望我扩展为答案,请告诉我. (3认同)
  • 是.我还在使用这种方法.没有找到更好的选择. (2认同)

ate*_*rel 6

虽然没有明确的私有关键字,但有一个惯例是将私有函数从单个下划线开始,但是双前导下划线将使其他人无法轻易地从模块外部调用该函数.请参阅PEP 8中的以下内容

- _single_leading_underscore: weak "internal use" indicator.  E.g. "from M
  import *" does not import objects whose name starts with an underscore.

- single_trailing_underscore_: used by convention to avoid conflicts with
  Python keyword, e.g.

  Tkinter.Toplevel(master, class_='ClassName')

- __double_leading_underscore: when naming a class attribute, invokes name
  mangling (inside class FooBar, __boo becomes _FooBar__boo; see below).

- __double_leading_and_trailing_underscore__: "magic" objects or
  attributes that live in user-controlled namespaces.  E.g. __init__,
  __import__ or __file__.  Never invent such names; only use them
  as documented.
Run Code Online (Sandbox Code Playgroud)

要使整个模块保密,请不要包含该__init__.py文件.

  • Aterrel,你的意思是"不包括在`__init __.py`"?是否意味着不要在`__init __.py`中放置语句`import mod_b`?如果是这样,那仍然无法解决我的问题.客户端仍然可以像公共模块一样导入`mod_b`:`import mypack.mod_b`.或者你的意思是什么? (6认同)
  • 因此它不会严格强制模块是私有的,就像单个下划线很弱一样。但如果没有显式导入它,它就不会显示,这仍然是相当私密的。我想你可以用两个前导下划线来命名该文件,但我从来没有玩过这个。 (2认同)
  • 感谢阿特雷尔的回复。我决定的解决方案是在“mypack”下创建一个子包“private”,并将我想要“隐藏”的所有模块放入其中。这符合我的目的,即通过隐藏所有不需要的内容,使我的代码更易于探索(例如通过智能感知)。 (2认同)

Joe*_*ley 6

在这种情况下需要注意的一件事是间接进口。如果在mypack

from mypack._mod_b import foo
foo()
Run Code Online (Sandbox Code Playgroud)

然后用户可以

from mypack import foo
foo()
Run Code Online (Sandbox Code Playgroud)

但仍然一无所知。我建议导入为

from mypack import _mod_b
_mod_b.foo()
Run Code Online (Sandbox Code Playgroud)

那么当用户尝试这样做时,他们会立即看到一个红旗

from mypack import _mod_b
Run Code Online (Sandbox Code Playgroud)

至于实际的目录结构,您甚至可以将 Jeremy 的答案扩展到一个_package_of_this_kind包中,其中的任何内容都可以有您喜欢的任何“访问修饰符” - 用户会知道有龙