访问限制
在 Class 内部, 可以有属性和方法, 而外部代码可以通过直接调用实例变量的方法来操作数据, 这样, 就隐藏了内部的复杂逻辑.
但是, 从前面 Student 类的定义来看, 外部代码还是可以自由地修改一个实例的 name,score 属性:
- >>> class Student(object):
- def __init__(self,name,score):
- self.name =name
- self.score = score
- >>> bart =Student('lixiao',12)
- >>> bart.score
- 12
- >>> bart.score=13
- >>> bart.score
- 13
如果要让内部属性不被外部访问, 可以把属性的名称前加上两个下划线__, 在 Python 中, 实例的变量名如果以__开头, 就变成了一个私有变量 (private), 只有内部可以访问, 外部不能访问, 所以, 我们把 Student 类改一改:
- >>> class Student(object):
- def __init__(self,name,score):
- self.__name = name
- self.__score = score
- def print11(self):
- print('%s:%s'%(self.__name,self.__score))
改完后, 对于外部代码来说, 没什么变动, 但是已经无法从外部访问实例变量.__name 和实例变量.__score 了:
- >>> bart =Student('da',12)
- >>> bart.__name
- Traceback (most recent call last):
- File "<pyshell#18>", line 1, in <module>
- bart.__name
- AttributeError: 'Student' object has no attribute '__name'
- >>>
这样就确保了外部代码不能随意修改对象内部的状态, 这样通过访问限制的保护, 代码更加健壮.
但是如果外部代码要获取 name 和 score 怎么办? 可以给 Student 类增加 get_name 和 get_score 这样的方法:
- class Student(object):
- def __init__(self,name,score):
- self.__name = name
- self.__score = score
- def print11(self):
- print('%s:%s'%(self.__name,self.__score))
- def get_name(self):
- return self.__name
- def get_score(self):
- return self.__score
如果又要允许外部代码修改 score 怎么办? 可以再给 Student 类增加 set_score 方法:
- class Student(object):
- ...
- def set_score(self, score):
- self.__score = score
你也许会问, 原先那种直接通过 bart.score = 99 也可以修改啊, 为什么要定义一个方法大费周折? 因为在方法中,
可以对参数做检查, 避免传入无效的参数
- class Student(object):
- def __init__(self,name,score):
- self.__name = name
- self.__score = score
- def print11(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):
- if 0<=score<=100:
- self.__score = score
- else:
- raise ValueError('bad score')
raise ValueError('bad score') 这个函数是异常处理的意思
需要注意的是, 在 Python 中, 变量名类似__xxx__的, 也就是以双下划线开头, 并且以双下划线结尾的, 是特殊变量, 特殊变量是可以直接访问的, 不是 private 变量, 所以, 不能用__name__,__score__这样的变量名.
有些时候, 你会看到以一个下划线开头的实例变量名, 比如_name, 这样的实例变量外部是可以访问的, 但是, 按照约定俗成的规定, 当你看到这样的变量时, 意思就是,"虽然我可以被访问, 但是, 请把我视为私有变量, 不要随意访问".
双下划线开头的实例变量是不是一定不能从外部访问呢? 其实也不是. 不能直接访问__name 是因为 Python 解释器对外把__name 变量改成了_Student__name, 所以, 仍然可以通过_Student__name 来访问__name 变量
- >>> bart._Student__name
- 'da'
但是强烈建议你不要这么干, 因为不同版本的 Python 解释器可能会把__name 改成不同的变量名.
总的来说就是, Python 本身没有任何机制阻止你干坏事, 一切全靠自觉.
最后注意下面的这种错误写法:
- >>> bart._Student__name
- 'da'
- >>> bart=Student('dada',12)
- >>> bart.get_name()
- 'dada'
- >>> bart.__name='new name'
- >>> bart.__name
- 'new name'
表面上看, 外部代码 "成功" 地设置了__name 变量, 但实际上这个__name 变量和 class 内部的__name 变量不是一个变量! 内部的__name 变量已经被 Python 解释器自动改成了_Student__name, 而外部代码给 bart 新增了一个__name 变量. 不信试试:
- >>> bart.get_name()
- 'dada'
练习
请把下面的 Student 对象的 gender 字段对外隐藏起来, 用 get_gender() 和 set_gender() 代替, 并检查参数有效性:
- class Student(object):
- def __init__(self, name, gender):
- self.__name = name
- self.__gender = gender
- def set_gender(self,gender):
- self.__gender =gender
- def get_gender(self):
- return self.__gender
- if K.get_gender()!='male':
- prnit('1')
- else:
- K.set_gender('female')
- if K.get_gender()!='female':
- print('1')
- else:
- print('0')
- 0
- 0x02
- class Student(object):
- def __init__(self, name, gender):
- self.name = name
- self.__gender = gender
- def get_gender(self):
- return self.__gender
- def set_gender(self, gender):
- if gender in {'male', 'female'}:
- self.__gender = gender
- else:
- raise ValueError('bad gender')
- 0x03
- class Student(object):
- def __init__(self, name, gender):
- self.name = name
- self.__gender = gender
- def get_gender(self):
- return self.__gender
- def set_gender(self,gender):
- if gender == 'male' or gender == 'female':
- self.__gender = gender
- else:
- print('bad gender!')
来源: http://www.bubuko.com/infodetail-3069756.html