跳到主要内容

访问限制

1. 为什么需要访问限制

  • 类内部有属性和方法,外部可通过实例变量操作数据;若属性直接暴露,外部可随意修改(如 bart.score = 99),内部逻辑无法保护。
  • 访问限制:把不希望被外部直接改动的属性设为“私有”,通过方法读写,便于封装参数校验,代码更健壮。

2. 私有变量:双下划线 __ 开头

  • 实例变量名以 两个下划线 __ 开头 → 视为私有变量(private)仅类内部可访问,外部不能直接访问。
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))
  • 外部访问 bart.__name 会报错:AttributeError: 'Student' object has no attribute '__name'

3. 对外提供 getter / setter

  • 读取:提供 get_name()get_score() 等方法返回私有属性。
  • 修改:提供 set_score(score) 等方法;在方法内可校验参数(如分数必须在 0~100),避免无效数据。
def get_name(self):
return self.__name

def get_score(self):
return self.__score

def set_score(self, score):
if 0 <= score <= 100:
self.__score = score
else:
raise ValueError('bad score')
  • 相比直接 bart.score = 99,通过 setter 可以在一处统一校验,更安全。

4. 命名约定与特殊变量

写法含义是否“私有”
__xxx__特殊变量(前后双下划线),如 __name____init__可直接访问,不要用作私有变量名
__xxx私有变量(仅前双下划线)类内私有,外部不直接访问
_xxx单下划线开头约定“视为私有”,外部可访问,但不建议随意访问
  • 不要__name____score__ 这种前后双下划线当作私有属性名,会与 Python 内置特殊变量冲突。

5. 双下划线的实现(了解即可)

  • 解释器会把 __name 改写_类名__name(如 _Student__name),所以理论上可通过 bart._Student__name 访问。
  • 强烈不建议依赖这种写法:不同版本解释器可能改名方式不同;应视为实现细节,遵守“不直接访问私有”的约定。

6. 常见错误:外部给实例加 __name

bart.__name = 'New Name'   # 表面“成功”
bart.__name # 'New Name'
bart.get_name() # 仍是 'Bart Simpson'
  • 类内部的 __name 已被改成 _Student__namebart.__name = 'New Name' 是给实例新增了一个属性 __name,与类内部的私有变量不是同一个
  • 正确做法:通过 set_xxx() 或提供的接口修改,不要在外边直接写 实例.__属性

7. 小结

  • 私有:属性名以 __ 开头(且不要用 __xxx__),通过 getter/setter 访问与校验。
  • 约定_xxx 视为“请勿随意访问”;Python 没有真正的访问强制,全靠约定和自觉

练习

Studentgender 对外隐藏,用 get_gender()set_gender() 代替,并做参数有效性检查(如只允许 'male' / 'female')。

class Student(object):
def __init__(self, name, gender):
self.name = name
self.gender = gender

# 测试
bart = Student('Bart', 'male')
if bart.get_gender() != 'male':
print('测试失败!')
else:
bart.set_gender('female')
if bart.get_gender() != 'female':
print('测试失败!')
else:
print('测试成功!')