57

我有一个mypack包含模块mod_a的包mod_b。我打算将包本身并mod_a自由导入:

import mypack
import mypack.mod_a

但是,我想mod_b保留mypack. 那是因为它的存在只是为了组织后者的内部代码。

我的第一个问题是,在 Python 编程中,拥有这样的“私有”模块是一种公认​​的做法吗?

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

4

5 回答 5

53

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

这与 PEP8 建议的相同精神(但不完全类似于)在被 Python 模块包装时使用前导下划线命名 C 扩展模块;即,_socketsocket

于 2012-02-14T23:17:27.137 回答
16

我决定的解决方案是创建一个子包“私有”并将我希望隐藏的所有模块放在那里。这样它们就可以被隐藏起来,让mypack's 的模块列表更清晰,更容易解析。

对我来说,这看起来也不奇怪。

于 2010-09-05T06:30:42.403 回答
11

虽然没有明确的私有关键字,但约定私有函数以单个下划线开头,但双前导下划线会使其他人无法轻松地从模块外部调用该函数。请参阅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.

要将整个模块设为私有,请不要将其包含在__init__.py文件中。

于 2010-08-30T21:26:11.660 回答
3

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

from mypack._mod_b import foo
foo()

然后用户可以

from mypack import foo
foo()

也不要更聪明。我建议导入为

from mypack import _mod_b
_mod_b.foo()

那么用户在尝试时会立即看到一个危险信号

from mypack import _mod_b

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

于 2019-09-30T22:38:23.230 回答
2

Python 并不严格了解或支持“私有”或“受保护”方法或类。有一个约定,以单个下划线为前缀的方法不是官方 API 的一部分,但我不会在类或文件上这样做——这很难看。

如果有人真的需要继承或访问 mod_b,为什么要阻止他/她这样做呢?您始终可以在您的文档和模块中的文档中提供一个您不应该直接访问它的首选 API,并改用 mypack。

于 2010-08-30T17:16:21.790 回答