那种仅限从一个对象内部访问的“私有”实例变量在Python中并不存在。大多数Python代码都遵循这样一个约定:带有一个下划线的名称(例如 _spam)应当被视为API的非公有部分(无论它是函数、方法或是数据成员)。这应当被视为一个细节。这样的实例变量外部是可以访问的,但是,按照约定俗成的规定,当你看到这样的变量时,意思就是,“虽然我可以被访问,但是,请把我视为私有变量,不要随意访问”。

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

例如:

class Student(object):
    """students' score"""
    def __init__(self, name, score):
        self.__name = name
        self.__score = score

    def print_score(self):
        print('%s: %s' %(self.__name, self.__score))

x = Student('lihua', 90)
print(x.__doc__)
x.print_score()
print(x.__name)

会出现这种情况:

students’ score
lihua: 90
Traceback (most recent call last):
File “C:/Users/David Wolfowitz/Desktop/gat/high——level/global_nonlocal”, line 13, in
print(x.__name)
AttributeError: ‘Student’ object has no attribute ‘__name’

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

如果想要修改score, 可以编写一个函数set_score,调用这个函数修改。

class Student(object):
    """students' score"""
    def __init__(self, name, score):
        self.__name = name
        self.__score = score

    def print_score(self):
        print('%s: %s' %(self.__name, self.__score))

    def get_name(self):
        return self.__name

    def get_score(self):
        return self.__score

    def set_score(self, score):
        self.__score = score

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

双下划线开头的实例变量是不是一定不能从外部访问呢?其实也不是。
由于存在对于类私有成员的有效使用场景(例如避免名称与子类所定义的名称相冲突),因此存在对此种机制的支持,称为名称改写。任何形式 __spam的标识符的文本将被替换成 _classname__spam,其中 classname 为去除了前缀下划线的当前类名称,这样改写不考虑标识符的句法位置,只要它出现在内部就会进行。
所以,不能直接访问__name是因为Python解释器对外把__name变量改成了_Student__name,所以,仍然可以通过_Student__name来访问__name变量:

print(x._Student__name)

lihua

最后注意下面的这种错误写法:

>>> bart = Student('Bart Simpson', 59)
>>> bart.get_name()
'Bart Simpson'
>>> bart.__name = 'New Name' # 设置__name变量!
>>> bart.__name
'New Name'

表面上看,外部代码“成功”地设置了__name变量,但实际上这个__name变量和class内部的__name变量不是一个变量!内部的__name变量已经被Python解释器自动改成了_Student__name,而外部代码给bart新增了一个__name变量。`

>>> bart.get_name() # get_name()内部返回self.__name
'Bart Simpson'