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

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

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

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

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

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

I am coding a small Python module composed of two parts:

  • some functions defining a public interface,
  • an implementation class used by the above functions, but which is not meaningful outside the module.

At first, I decided to “hide” this implementation class by defining it inside the function using it, but this hampers readability and cannot be used if multiple functions reuse the same class.

So, in addition to comments and docstrings, is there a mechanism to mark a class as “private” or “internal”? I am aware of the underscore mechanism, but as I understand it it only applies to variables, function and methods name.


回答 0

使用单个下划线前缀:

class _Internal:
    ...

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

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

Use a single underscore prefix:

class _Internal:
    ...

This is the official Python convention for ‘internal’ symbols; “from module import *” does not import underscore-prefixed objects.

Edit: Reference to the single underscore convention


回答 1

简而言之:

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

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

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

想要查询更多的信息:

In short:

  1. You cannot enforce privacy. There are no private classes/methods/functions in Python. At least, not strict privacy as in other languages, such as Java.

  2. You can only indicate/suggest privacy. This follows a convention. The python convention for marking a class/function/method as private is to preface it with an _ (underscore). For example, def _myfunc() or class _MyClass:. You can also create pseudo-privacy by prefacing the method with two underscores (eg: __foo). You cannot access the method directly, but you can still call it through a special prefix using the classname (eg: _classname__foo). So the best you can do is indicate/suggest privacy, not enforce it.

Python is like perl in this respect. To paraphrase a famous line about privacy from the Perl book, the philosophy is that you should stay out of the living room because you weren’t invited, not because it is defended with a shotgun.

For more information:


回答 2

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

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

Define __all__, a list of names that you want to be exported (see documentation).

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

回答 3

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

定义一个类:

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

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

x = x()

定义公开功能的符号:

doThis = x.doThis
doThat = x.doThat

删除实例本身:

del x

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

A pattern that I sometimes use is this:

Define a class:

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

Create an instance of the class, overwriting the class name:

x = x()

Define symbols that expose the functionality:

doThis = x.doThis
doThat = x.doThat

Delete the instance itself:

del x

Now you have a module that only exposes your public functions.


回答 4

约定在内部类,函数和变量之前加“ _”。

The convention is prepend “_” to internal classes, functions, and variables.


回答 5

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

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

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

To address the issue of design conventions, and as Christopher said, there’s really no such thing as “private” in Python. This may sound twisted for someone coming from C/C++ background (like me a while back), but eventually, you’ll probably realize following conventions is plenty enough.

Seeing something having an underscore in front should be a good enough hint not to use it directly. If you’re concerned with cluttering help(MyClass) output (which is what everyone looks at when searching on how to use a class), the underscored attributes/classes are not included there, so you’ll end up just having your “public” interface described.

Plus, having everything public has its own awesome perks, like for instance, you can unit test pretty much anything from outside (which you can’t really do with C/C++ private constructs).


回答 6

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

class _MyInternalClass:
    def __my_private_method:
        pass

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

Use two underscores to prefix names of “private” identifiers. For classes in a module, use a single leading underscore and they will not be imported using “from module import *”.

class _MyInternalClass:
    def __my_private_method:
        pass

(There is no such thing as true “private” in Python. For example, Python just automatically mangles the names of class members with double underscores to be __clssname_mymember. So really, if you know the mangled name you can use the “private” entity anyway. See here. And of course you can choose to manually import “internal” classes if you wanted to).