结论先行
在Python中,允许子类使用的内部属性(单下划线开头)类似于Java的保护变量,不允许子类使用的内部属性(双下划线开头)类似于Java的私有变量。
背景概念
函数:在类外部定义的函数
方法:在类内部定义的函数,通常第一个参数默认为self或cls
变量:在类外部定义的变量
属性:在类内部定义的变量,通过【实例.属性名】,或【类.属性名】的格式才能调用
公开接口与内部接口
Python将接口(包,模块,类,函数、变量)区分为两种类型:public(公开) 和 internal / non-public(内部 / 非公开)。
公开接口是允许项目外部用户使用的接口,项目开发者承诺未来对公开接口所做的变更一定是向后兼容的。
内部接口是只有项目内部团队可以使用的、不打算被项目外部用户使用的接口,项目开发者不保证未来对内部接口所做的变更一定是向后兼容的。
由于只有公开接口才有向后兼容性保证。因此,需要有标志让用户能够清楚地区分公开和内部接口。
五种区分标志
- 提供了说明文档的接口一般视为公开接口,除非文档明确声明此接口是临时或内部接口,不保证向后兼容。所有不提供说明文档的接口视为内部接口。
- 本模块从其他模块中导入的接口一般视为本模块的内部接口。除非本模块在说明文档中明确声明此接口是公开接口。
- 如果一个命名空间(包,模块,或类)被认为是内部接口,则它所包含的接口(变量、函数)都视为内部接口。
- 在模块中使用__all__属性显示声明的接口视为公开接口, __all__设置为一个空列表表示该模块没有公开接口。
- 名称有前导下划线的接口视为内部接口。
限制措施
如果设置了__all__属性,则from M import *
只导入__all__属性中指定的接口;如果未设置__all__属性,则from M import *
只导入名称里没有前导下划线的接口。
但是如果__all__属性中包含了名称有前导下划线的接口,from M import *
仍然可以导入;或者使用import M
和from M import _var, _func, _SomeClass
这两种方式都能导入名称有前导下划线的接口,所以这种限制措施不是强制的,主要还是靠自觉。
公开属性(方法)与内部属性(方法)
对于在类内部定义的属性、方法,Python也是将其区分为公开、内部这两种类型,含义与公开接口、内部接口相同,即是否提供向后兼容保证。
区分标志为属性(方法)名称是否有前导下划线。
此外,内部属性(方法)又根据是否允许子类使用细分为两种。
在Python中没有强制措施限制对内部属性(方法)的调用,纯靠自觉,因而也就不存在真正的保护变量、私有变量,只能说是类似于Java的保护变量、私有变量。
下划线含义总结
- 单前导下划线:“内部使用”标志,加在接口或属性(方法)的名称之前,意味着项目开发者不保证未来对该接口或属性(方法)所做的变更一定是向后兼容的。
- 双前导下划线:加在属性(方法)的名称之前,意味着不允许子类使用。
- 单后置下划线:用于避免与Python关键字冲突,加在冲突名称之后,例如
Tkinter.Toplevel(master, class_='ClassName')
。 - 前导和后置都是双下划线:Python保留的魔术方法或特殊属性。例如:__ init__,__ import__或__ file__,__ all__。;只要按照说明文档使用这些魔术方法或特殊属性就行,不要自己创造这样的名字。