Python中没有访问控制的关键字,例如private、protecte和public等。但是在Python编码中,通过遵循一定的变量、属性和方法命名规约来进行访问控制。这样定义的变量、属性和方法要么是public,要么就是private,但是python中的private不像C++、Java那样,它并不是真正意义上的private。这主要通过单下划线”_”和双下划线”__”实现。
单下划线”_”做为前缀
这个被常用于模块中,在一个模块中以单下划线开头的变量、函数或类中的属性和方法被默认当作内部实现,如果使用from module_name import *或import
modulename导入时,这部分变量和函数/方法不会被导入,除非模块/包的__all__列表明确包含了这些名称,即在模块的末尾定义变量__all__(双下划线)来明确地列出需要导出的内容,格式为
__all__=[‘name1’,’ name2’,…’namen’]
如下一个文件moduletest.py
[root@localhost~]# vi moduletest.py
commonvar=100
_var=12
def_fun():
pass
classPrivate():
commonclassvar="class var"
_classvar="as a private var"
def __init__(self):
self.selfvar=12
def _funclass(self):
return "as a private method"
在当前路径下开启一个shell
[root@localhost~]# python
Python2.7.5 (default, Jun 20 2019, 20:27:34)
[GCC4.8.5 20150623 (Red Hat 4.8.5-36)] on linux2
Type"help", "copyright", "credits" or"license" for more information.
>>>from moduletest import *
>>>dir()
['Private','__builtins__', '__doc__', '__name__', '__package__', 'commonvar']
>>>
可见以“_”为前缀的变量和函数都不会被导入。
模块中带有“_”的变量、函数或类中带有“_”的属性或方法,仅用来标明这些是一些模块中使用的私有变量和函数或类中的私有变量或方法,但在模块外部,通过模块名或类名、实例都可以访问到这些私有变量、函数或方法。如
>>> pr=Private()
>>> pr._funclass()
'as a private method'
>>>
>>> import moduletest
>>> moduletest._var
12
>>> moduletest._var=13
>>> moduletest._var
13
>>>
双下划线”__”作为前缀
以双下划线开头的命名形式在 Python 的类成员中表示名字改编 (Name
Mangling),它对解释器有特定含义。Python会改写这些名称,以免与子类中定义的名称产生冲突。Python documentation中提到,任何__spam这种形式(至少以两个下划线做开头,最多有一个下划线做结尾)的标识符,都会文本上被替换为_classname__spam,其中classname是当前类名,并带上一个下划线做前缀。
这就是所谓的私有变量改编(Private name mangling)。转换机制是这样的:在变量前端插入类名,再在前端加入一个下划线字符。通过name mangling(名称改编)目的就是以防子类意外重写基类的方法属性或者数据属性,这些属性通过继承无法被子类的同名数据属性或方法覆盖。如下一个经典类(在python2.x下编写)
>>> class Man():
... clsvar='test'
_svar='_test'
... __var=12
... def __manselffun(self):
... print('man self fun')
... def retprivatevar(self):
... returnself.clsvar+str(self.__var)
...
我们查看它的属性
>>> man=Man()
>>> dir(man)
['_Man__manselffun', '_Man__var', '__doc__', '__module__', '_svar', 'clsvar','retprivatevar']
>>>
可见,以双下划线开头的属性,都经过了名字改编。
因此应该注意一般函数不要使用两个前导下划线(当遇到两个前导下划线时,Python 的名称改编特性将发挥作用)。
上面提到有两种不同的编码约定(单下划线和双下划线) 来命名私有属性,那么问题就来了:到底哪种方式好呢?大多数而言,你应该让你的非公共名称以单下划线开头。但是,如果你清楚你的代码会涉及到子类,并且有些父类的内部属性应该在子类中隐藏起来,那么才考虑使用双下划线方案。如
>>> class Boy(Man):
... def __manselffun(self):
... return 'boy'
...
>>> dir(Boy)
['_Boy__manselffun', '_Man__manselffun', '_Man__var', '__doc__','__module__', '_svar', 'clsvar', 'retprivatevar']
可以看出,父类的__manselffun方法属性和通过继承后属性名在两个类中的名字是完全不一样的,即父类的属性在子类中被隐藏了,子类无法覆盖父类的同名__manselffun方法属性。
网友评论