一、Python中默认的成员函数、成员变量都是公开的(public),而且python中没有类似public、private等关键词来修饰成员函数,成员变量。
在python中定义私有变量只需要在变量名或函数名前加上 "__" (两个下划线),那么这个函数或变量就会成为私有的了。
在内部,python使用一种 name mangling 技术,将__membername替换成 _classname__membername,所以你在外部使用原来的私有成员的名字时,会提示找不到。
命名混淆意在给出一个在类中定义"私有"实例变量和方法的简单途径,避免派生类的实例变量定义产生问题,或者与外界代码中的变量搞混。
要注意的是混淆规则主要目的在于避免意外错误,被认作为私有的变量仍然有可能被访问或修改(使用_classname__membername),在特定的场合它也是有用的,比如调试的时候。
【示例代码】
# -*- coding: utf-8 -*-
class Test(object):
def __init__(self):
super(Test, self).__init__()
self.__member = 99
def __method(self):
print "Test.__method"
if __name__ == '__main__':
t = Test()
print dir(t)
#t.__method() # AttributeError: 'Test' object has no attribute '__method'
#print t.__member # AttributeError: 'Test' object has no attribute '__member'
t._Test__method() # 使用Python更改之后的函数名依然可以访问到"私有"函数
print t._Test__member # 使用Python更改之后的变量名依然可以访问到"私有"变量
'''
['_Test__member', '_Test__method', '__class__', '__delattr__', '__dict__', '__doc__', '__format__', '__getattribute__', '__hash__', '__init__', '__module__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__']
Test.__method
99
'''
可以看到在dir里面多的不是__member和__method,而是_Test__member和_Test__method。并且可以通过_Test__member和_Test__method访问原来类里面的成员变量和成员函数。
二、单下划线开头的成员变量和成员函数,其实就是public的,不等同于protected属性。
【示例代码】
# -*- coding: utf-8 -*-
class Test(object):
def __init__(self):
super(Test, self).__init__()
self.__member = 88
self._member = 99
def __method(self):
print "Test.__method"
def _method(self):
print "Test._method"
class TestDerived(Test):
def __init__(self):
super(TestDerived, self).__init__()
def test(self):
#print self.__member # AttributeError: 'TestDerived' object has no attribute '_TestDerived__member'
#self.__method() # AttributeError: 'TestDerived' object has no attribute '_TestDerived__method'
print self._member
self._method()
if __name__ == '__main__':
td = TestDerived()
print dir(td)
td.test()
#print td.__member # AttributeError: 'TestDerived' object has no attribute '__member'
#td.__method() # AttributeError: 'TestDerived' object has no attribute '__method'
print td._member # 外部可以直接访问单下划线开头的成员变量
td._method() # 外部可以直接访问单下划线开头的成员函数
'''
['_Test__member', '_Test__method', '__class__', '__delattr__', '__dict__', '__doc__', '__format__', '__getattribute__', '__hash__', '__init__', '__module__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', '_member','_method', 'test']
99
Test._method
99
Test._method
'''
无论是单下划线还是双下划线开头的成员,都是希望外部程序开发者不要直接使用这些成员变量和这些成员函数,只是双下划线从语法上能够更直接的避免错误的使用,但是如果按照 _类名__成员名 则依然可以访问到。单下划线的在动态调试时可能会方便一些,只要项目组的人都遵守下划线开头的成员不直接使用,那使用单下划线或许会更好。