你是如何区分外部调用的方法和子类调用的方法的?

1 投票
3 回答
1484 浏览
提问于 2025-04-11 09:33

我对Python中私有变量、成员和函数的用法大致了解。

不过,我一直在想,怎么区分哪些方法是给外部使用的,哪些是给子类使用的。

看看这个例子:

class EventMixin(object):
    def subscribe(self, **kwargs):
        '''kwargs should be a dict of event -> callable, to be specialized in the subclass'''

    def event(self, name, *args, **kwargs):
        ...

    def _somePrivateMethod(self):
        ...

在这个例子中,我想明确表示,subscribe是一个外部用户可以使用的方法,而event是一个不应该被外部调用的方法,它应该由子类来实现。

目前,我认为这两个方法都是公共接口的一部分,所以我没有使用下划线。不过,对于这种情况,我觉得如果外部接口不加下划线,子类接口加一个下划线,而私有内部接口加两个下划线,这样会更清晰。但这样做会让事情变得复杂,因为内部接口就需要这样调用:

self._EventMixin__somePrivateMethod()

那么,你们在编码、文档或者其他方面有什么约定吗?

3 个回答

2

我想建议一下,当你遇到这种区别时,考虑使用组合而不是继承可能是个好主意。换句话说,可以考虑实例化 EventMixin(这个名字可能会改)而不是去继承它。

2

我觉得用双下划线(__)会带来更多麻烦,反而不值得,因为这会让单元测试变得非常困难。我更喜欢用单下划线(_)作为约定,来表示某些方法或属性不打算作为某个类或模块的公共接口的一部分。

3
use no underscores for the external API,
one underscore for the subclassable API,
and two underscores for the private/internal API

这是一个合理且相对常见的做法,没错。用双下划线来表示“真正私有”的属性(和C++中的“保护”属性相对)其实在实际中是比较少见的。你永远不知道子类会想要覆盖哪些行为,所以一般来说,假设使用“保护”属性是个不错的选择,除非有特别好的理由说明修改某个成员会特别危险。

However, that would become unwieldy because then the internal API would
need to be invoked as self._EventMixin__somePrivateMethod()

不,你可以直接使用双下划线的版本,它会自动处理。虽然看起来不太好,但确实有效。

撰写回答