【问题标题】:"Private" (implementation) class in PythonPython中的“私有”(实现)类
【发布时间】:2010-10-07 18:05:02
【问题描述】:

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

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

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

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

【问题讨论】:

    标签: python access-modifiers


    【解决方案1】:

    使用单个下划线前缀:

    class _Internal:
        ...
    

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

    编辑:参考single underscore convention

    【讨论】:

    • 我不知道下划线规则扩展到类。我不想在导入时弄乱我的命名空间,所以我一直在寻找这种行为。谢谢!
    • 既然您声明这是“官方”python 约定,最好有一个链接。此处的另一篇文章说 all 是官方方式,并且确实链接到文档。
    • python.org/dev/peps/pep-0008 -- _single_leading_underscore:弱“内部使用”指标。例如。 “from M import *”不导入名称以下划线开头的对象。 -- 内部使用的类有一个前导下划线
    • 前导下划线是将事物标记为内部的约定,“不要乱用这个”,而 all 更多地用于设计为与“from M”一起使用的模块import *",不一定暗示模块用户不应该接触该类。
    • 这不能按预期工作,类仍然可以导入
    【解决方案2】:

    简而言之:

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

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

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

    更多信息:

    【讨论】:

    • 响应#1,您可以强制执行方法的隐私。使用像 __method(self) 这样的双下划线会使其在类外无法访问。但是有一种方法可以通过调用它,比如 Foo()._Foo__method()。我猜它只是将它重命名为更深奥的东西。
    【解决方案3】:

    定义__all__,您要导出的名称列表 (see documentation)。

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

    【讨论】:

      【解决方案4】:

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

      定义一个类:

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

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

      x = x()
      

      定义公开功能的符号:

      doThis = x.doThis
      doThat = x.doThat
      

      删除实例本身:

      del x
      

      现在你有了一个只公开你的公共函数的模块。

      【讨论】:

      • 花了一分钟了解“覆盖类名”的目的/功能,但当我这样做时,我笑了。不知道什么时候用。 :)
      • 这种技术有名字吗?
      • 我不明白这一点。有人可以提供完整的代码供我试用吗?
      • 天啊,这真是一个黑客。请永远不要这样做。太酷了
      【解决方案5】:

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

      【讨论】:

        【解决方案6】:

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

        class _MyInternalClass:
            def __my_private_method:
                pass
        

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

        【讨论】:

        • 为什么是两个_?一个就够了。
        • 一个下划线就足以防止“import”导入类和函数。您需要两个下划线来诱导 Python 的名称修饰功能。应该更清楚;我编辑了。
        • 现在,跟进。为什么要改名?这样做有什么好处?
        • 可能的好处是惹恼其他需要访问这些变量的开发人员:)
        【解决方案7】:

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

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

        另外,将所有内容都公开有其自身很棒的好处,例如,您可以从外部对几乎所有内容进行单元测试(使用 C/C++ 私有结构实际上无法做到这一点)。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2015-07-17
          • 2017-11-06
          • 2015-10-27
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多