134

我正在编写一个由两部分组成的小型 Python 模块:

  • 一些定义公共接口的函数,
  • 上述函数使用的实现类,但在模块外没有意义。

起初,我决定通过在使用它的函数中定义它来“隐藏”这个实现类,但这会妨碍可读性,并且如果多个函数重用同一个类,则无法使用。

那么,除了注释和文档字符串之外,是否还有一种机制可以将类标记为“私有”或“内部”?我知道下划线机制,但据我了解,它仅适用于变量、函数和方法名称。

4

7 回答 7

212

使用单个下划线前缀:

class _Internal:
    ...

这是“内部”符号的官方 Python 约定;"from module import *" 不导入带下划线前缀的对象。

参考单下划线约定

于 2009-02-15T15:34:03.643 回答
85

简而言之:

  1. 您不能强制执行隐私。Python 中没有私有类/方法/函数。至少,不像 Java 等其他语言那样严格的隐私。

  2. 您只能表明/建议隐私。这遵循一个约定。将类/函数/方法标记为私有的 Python 约定是在其前面加上 _(下划线)。例如,def _myfunc()class _MyClass:__foo您还可以通过在方法前加上两个下划线(例如, )来创建伪隐私。您不能直接访问该方法,但您仍然可以使用类名通过特殊前缀调用它(例如,_classname__foo)。所以你能做的最好的就是表明/建议隐私,而不是强制执行。

Python 在这方面就像Perl。套用 Perl 书中关于隐私的一句名言,哲学是你应该呆在客厅外面,因为你没有被邀请,而不是因为它被猎枪保护了。

了解更多信息:

于 2009-02-15T18:31:49.783 回答
44

定义__all__,您要导出的名称列表(请参阅文档)。

__all__ = ['public_class'] # don't add here the 'implementation_class'
于 2009-02-15T15:36:03.030 回答
16

我有时使用的模式是这样的:

定义一个类:

class x(object):
    def doThis(self):
        ...
    def doThat(self):
        ...

创建类的实例,覆盖类名:

x = x()

定义公开功能的符号:

doThis = x.doThis
doThat = x.doThat

删除实例本身:

del x

现在您有了一个只公开您的公共功能的模块。

于 2009-02-15T15:58:49.027 回答
11

约定是在内部类、函数和变量前面加上“_”。

于 2009-02-15T15:33:48.260 回答
6

使用两个下划线作为“私有”标识符名称的前缀。对于模块中的类,使用单个前导下划线,它们不会使用“from module import *”导入。

class _MyInternalClass:
    def __my_private_method:
        pass

(在 Python 中没有真正的“私有”这样的东西。例如,Python 只是自动将带有双下划线的类成员的名称修改为__clssname_mymember. 所以说真的,如果你知道被修改的名称,你无论如何都可以使用“私有”实体.见这里。当然,如果您愿意,您可以选择手动导入“内部”类)。

于 2009-02-15T16:37:01.340 回答
5

为了解决设计约定的问题,正如chroder 所说,Python 中确实没有“私有”这样的东西。对于来自 C/C++ 背景的人(就像我不久前一样)来说,这听起来可能有些扭曲,但最终,您可能会意识到遵循约定就足够了。

看到前面有下划线的东西应该是一个很好的暗示,不要直接使用它。如果您关心混乱的help(MyClass)输出(这是每个人在搜索如何使用类时都会看到的),那么下划线的属性/类不包括在那里,因此您最终只会描述您的“公共”接口。

另外,让所有东西都公开有它自己很棒的好处,例如,你可以从外部对几乎任何东西进行单元测试(你不能用 C/C++ 私有结构真正做到这一点)。

于 2009-02-15T18:09:59.727 回答