python类的私有变量

        在python中可以通过在属性变量名前加上双下划线定义属性为私有属性。

        特殊变量命名

  1. _xx以但下划线开头的表示protected类型的变量。即保护类型只能允许其本身与子类进行访问。若内部变量标示。如:当使用“from M import”时,不会将以一个下划线开头的变量引入。
  2. __xx双下划线的表示是私有类型的变量。只能允许这个类本身进行访问。连子类也不可以用于命名一个类属性(类变量)。调用时名字被改变(在类FooBar内部,boo变成_FooBarboo,如self._FooBar__boo).
  3. __xx__定义的是特殊方法。用户控制的命名空间内的变量或是属性,如init,import或是file。只有当文档有说明时使用,不要自己定义这类变量。(就是说这些是python内部定义的变量名)

        在class内部,可以有属性和方法,而外部可以通过直接调用实例变量的方法来操作数据,这样,就隐藏了内部的复杂逻辑。

1
2
3
4
5
6
7
8
class Student(object):
def __init__(self, name, score):
self.name = name
self.score = score
def print_score(self):
print '%s: %s' % (self.name, self.score)

        但是,从Student类的定义来看,外部代码还是可以自由的修改一个实例的namescore属性

1
2
3
4
5
6
>>> bart = Student('Bart Simpson', 98)
>>> bart.score
98
>>> bart.score = 59
>>> bart.score
59

        如果要让内部属性不被外部访问,可以把属性的名称前加上两个下划线__,在python中实例的变量名如果以__开头,就编程了一个私有变量(private),只有内部可以访问,外部不能访问

1
2
3
4
5
6
7
8
class Student(object):
def __init__(self, name, score):
self.__name = name
self.__score = score
def print_score(self):
print '%s: %s' % (self.__name, self.__score)

        改完后,对于外部代码来说,已经无法从外部访问实际变量.__name实际变量.__score

1
2
3
4
5
>>> bart = Student('Bart Simpson', 98)
>>> bart.__name
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'Student' object has no attribute '__name'

        这样就确保了外部代码不能随意修改对象内部的状态,这样通过访问限制的保护,代码更加健壮

        但是如果外部代码要获取name和score,可以给Student类增加get_nameget_score这样的方法

1
2
3
4
5
6
7
8
class Student(object):
...
def get_name(self):
return self.__name
def get_score(self):
return self.__score

        如果要允许外部代码修改score,可以给Student类增加set_score方法

1
2
3
4
5
class Student(object):
...
def set_score(self, score):
self.__score = score

        为什么要定义一个方法这么麻烦?因为在方法中,可以对参数做检查,避免传入无效的参数

1
2
3
4
5
6
7
8
class Student(object):
...
def set_score(self, score):
if 0 <= score <= 100:
self.__score = score
else:
raise ValueError('bad score')

        需要注意的是,在python中,变量名类似__xxx__的,也就是以双下划线开头,并且以双下划线结尾的,是特殊变量,特殊变量是可以直接访问的,不是private变量,所以,不能用__name____score__这样的变量名。

        有些时候,会看到以一个下划线开头的实例变量名,比如_name,这样的实例变量外部是可以访问的,但是按照约定的规定,当看到这样的变量时,意思就是,“虽然可以被访问,但是,要视为私有变量,不要随意访问”。

        双下划线开头的实例变量也不是一定不能从外部访问。不能直接访问__name是因为python解释器对外把__name变量改成了_Student__name,所以,仍然可以通过_Student__name来访问__name变量

1
2
>>> bart._Student__name
'Bart Simpson'

        不过不建议这么赶,因为不同版本的python解释器可能会把__name改成不同的变量名。