【问题描述】:

背景

几周前,我用 Python 完成了一项技术测试。虽然测试的总体反馈非常积极,但我在反馈中看到的一件令我惊讶的事情是:

<1234565>

没有封装——大量的 public_functions 应该是 _private_functions

这让我感到惊讶,因为 - 根据我作为 Python 开发人员两年来在脑海中建立的模糊画面 - 我们真的不做私有Python 中的方法或函数。我们所拥有的只是各种公约、速记和君子协定的拼凑。但我脑海中的那个画面对吗?

下划线和双下划线

所以我对此事进行了更深入的调查,咨询了the standard Python documentationPEP 8,我得出了以下结论:

  1. 在类属性调用 name mangling 之前使用 双下划线,即 __spam 将被解释作为 _classname__spam。这可以用来模拟一种粗略的隐私,这样如果一个人试图从其类之外调用 __spam,就会引发异常。
  2. 程序员可以使用单下划线来表示函数(或类似函数)是私有的,但这似乎对句法影响不大。 PEP 8 提到在调用 from M import * 时不会导入 _single_leading_underscore,但我找不到其他任何东西。

但是,这只是告诉我我能做什么,而不是我应该做什么。

我想知道的

我是否可以将上述反馈视为来自可能在 Java/C#/etc 中度过其职业生涯的人,因此在 Python 中封装时没有正确的心态?或者我应该重新思考我编写 Python 程序的方式,以便任何封装都更加明确?

【问题讨论】:

  • 这些是方法还是模块级函数?模块级函数使用前导下划线比方法少得多。
  • 方法上的前导下划线可能只是对其他开发人员的信号,但信号值得发送。
  • 似乎是基于意见的反馈。没有要求或期望在 Python 中拥有“私有”函数,除非情况特别需要它。也许反馈的作者正试图将他们对另一种语言的期望翻译成 Python。但这当然取决于您的功能和规格实际上是什么。
  • 仅仅因为 Python 没有使方法私有化的正式机制并不意味着考虑公共接口仍然不是设计代码库中组件的重要部分,尤其是那些会被其他人吃掉。是的,用户仍然可以访问 _semi_private__name_manangled 属性,但该约定告诉他们这不是接口的可靠部分,因此您可以对其进行重构。
  • 这样想,如果你有一个有 15 个方法的类,那么该类的用户是否应该实际上打算调用这 15 个方法中的任何一个?还是真的有 3-4 个“公共”方法,而其他 11-12 个是“私有”辅助方法?这种设计有助于使您的界面保持小而具体,而不会混淆实现细节。

标签: python oop private encapsulation


【解答1】:

从技术角度来看,编写代码的方式没有对错之分。计算机关心的是指令和数据。无论您是否使用 clases,如果您的代码是模块化的或意大利面条式的,您的函数的名称是什么,它们是公共的还是私有的等等 - 当它到达 CPU 时,这一切都付诸东流了。

像这样的争论是关于观点的争论。每个人都有意见。你也可以称之为味道。具有相似观点的人聚集在一起,创建组织、政党、机构等来宣传他们的想法。他们声称以某种方式可以概括和提炼软件的编写方式,将其归纳为“正确”或“错误”的决策。

然而,对于每条证明某事的规则,您很快就会发现另一条与之相矛盾的规则。这只是自然法则——现实没有界限。这是所有混乱的原因。

没有关于某事的普遍规则,而且永远不会有。这将与宇宙的本质相矛盾:时间和熵。无论您问什么问题,答案总是“视情况而定”。

经过 40 年的编程,我的核心价值观归结为:

  • 一致性比风格更重要。
  • 让读者更容易理解您在做什么,更重要的是,为什么。
  • 在正确的地方发表好评论可以省去一周的麻烦。
  • 读者可能就是你。
  • 始终尝试为工作选择最佳工具。
  • 在合理的地方遵循约定,但如果有正当理由,请不要犹豫违反规则。
  • 没有人比编写代码的人更清楚什么是有意义的。不断问自己:我所做的事情是否有意义,或者我是否看到了更好的方法?
  • 少即是多。

【问题讨论】:

    【解答2】:

    长话短说是听反馈。虽然 Python 确实没有像 C++ 或 Java 那样真正做到隐私保护,但它仍然向开发人员和用户发送信号,表明其意图是什么。公共属性可以以任何方式设置,如果您总是期望“object.x”是一个整数并将其设为字符串,这可能会导致错误。当一个属性被设为私有时(虽然不是真正私有的)意味着用户不能直接访问它,并且必须使用提供的处理程序。处理程序方法提供了唯一的访问方式,并且要求所有交互都使用相同的通道。同样的想法也适用于方法。有些方法是用户/开发人员永远不需要直接使用的,为了简化封装,这些方法应该是私有的。虽然并非完全必要,但使用 Python 的隐私功能确实有助于封装并有助于防止发生不可预见的错误。

    【问题讨论】: