Python中的“私有”(实现)类


105

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

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

首先,我决定通过在使用它的函数内部定义该实现类来“隐藏”该实现类,但这会影响可读性,并且如果多个函数重用同一类,则无法使用该实现类。

因此,除了注释和文档字符串外,是否存在将类标记为“私有”或“内部”的机制?我知道下划线机制,但据我了解,它仅适用于变量,函数和方法名称。

Answers:


172

使用单个下划线前缀:

class _Internal:
    ...

这是“内部”符号的官方Python约定;“从模块导入*”不会导入下划线前缀的对象。

编辑:引用单个下划线约定


3
我不知道下划线规则扩展到了类。导入时,我不想弄乱我的名称空间,所以这种行为正是我想要的。谢谢!
oparisy

1
由于您声明这是“官方” python约定,因此使用链接会很好。这里的另一篇文章说,一切都是官方的方式,并且确实链接到文档。
flodin

11
python.org/dev/peps/pep-0008-_single_leading_underscore:“内部使用”指示器较弱。例如,“从M import *”不会导入名称以下划线开头的对象。-内部使用的类的下划线是领先的
Miles

2
前面的下划线是用于标记事物的内部会议,“不乱用这个”,而所有的则多为设计与使用“的M进口*”的模块,而不一定意味着该模块的用户应不能触及那堂课
英里

65

简而言之:

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

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

在这方面,Python就像perl。用Perl的书来解释关于隐私的著名观点,其哲学是您应该离开客厅是因为没有邀请您,而不是因为它是由a弹枪保护的。

想要查询更多的信息:


作为对#1的回应,您可以强制执行方法的保密性。使用__method(self)之类的双下划线将使其在类外部不可访问。但是可以通过调用Foo()._ Foo__method()之类的方法来解决它。我想它只是将其重命名为更深奥的东西。
Evan Fosmark 09年

1
那句话是正确的。
Paul Draper

37

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

__all__ = ['public_class'] # don't add here the 'implementation_class'

10

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

定义一个类:

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

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

x = x()

定义公开功能的符号:

doThis = x.doThis
doThat = x.doThat

删除实例本身:

del x

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


2
花了一点时间来理解“覆盖类名”的目的/功能,但是当我这样做的时候我笑了。不知道何时使用。:)
扎克·杨

这个技术有名字吗?
比什瓦斯·米什拉


4

正如克里斯托弗所说,为了解决设计约定的问题,在Python中确实没有“私有”之类的东西。对于来自C / C ++背景的人来说,这听起来可能有点扭曲(就像我前阵子一样),但是最终,您可能会意识到遵循约定已经足够了。

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

另外,公开的一切都有其令人敬畏的特权,例如,您可以从外部对几乎所有内容进行单元测试(使用C / C ++私有结构实际上无法做到)。


4

使用两个下划线为“专用”标识符的名称添加前缀。对于模块中的类,请使用单个下划线,并且不会使用“ from module import *”来导入它们。

class _MyInternalClass:
    def __my_private_method:
        pass

(在Python中没有真正的“私有”之类的东西。例如,Python只是自动将带有双下划线的类成员的名称修改为__clssname_mymember。因此,实际上,如果您知道名称不正确,则无论如何都可以使用“私有”实体。看到这里。当然,你可以选择手动输入“内部”类,如果你想)。


为什么要两个_?一个就足够了。
S.Lott

单个下划线足以防止“ import”导入类和函数。您需要两个下划线才能引入Python的名称修饰功能。应该更清楚了;我编辑了。
chroder

现在,进行后续。为什么要改名?这可能带来什么好处?
S.Lott

5
可能的好处是使需要访问这些变量的其他开发人员感到烦恼:)
Richard Levasseur
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.