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

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

>>> bart = Student('Bart Simpson', 59)
>>> bart.score
59
>>> bart.score = 99
>>> bart.score
99

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

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了:

>>> bart = Student('Bart Simpson', 59)
>>> 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这样的方法:

class Student(object):
... 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 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变量:

>>> bart._Student__name
'Bart Simpson'

因为不同版本的Python解释器可能会把__name改成不同的变量名,所以不要这么做。

总的来说就是,Python本身没有任何机制阻止你干坏事,一切全靠自觉。

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

>>> 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'

最新文章

  1. BZOJ4416: [Shoi2013]阶乘字符串
  2. 直接通过Ajax 处理程序加 Action名,取得变量值。
  3. OutputCache属性详解(二)一 Location
  4. JS验证URL正则
  5. openoffice从word转pdf问题
  6. Asp.net mvc web api 在项目中的实际应用
  7. 启用 CORS 来解决这个问题(ajax跨域请求)
  8. android studio集成环境搭建
  9. javascript 如何避免属性访问错误
  10. signedCookies
  11. 软件测试博客日记Day02-11.16日 —— 赵天宇 —— 禅道的使用和配置
  12. [COGS 2583]南极科考旅行
  13. 2018-北航-面向对象-前三次OO作业分析与小结
  14. mysql学习笔记五 —— MHA
  15. Winform下载文件并显示进度条
  16. 数据科学VS机器学习
  17. 【转】再讲IQueryable&lt;T&gt;,揭开表达式树的神秘面纱
  18. 2018.07.10NOIP模拟 Knapsack(单调队列优化dp)
  19. IDEA开发web程序配置Tomcat
  20. sublime插件时间

热门文章

  1. 阿里云centos7安装python3.7.4和pip3
  2. linux环境下的Oracle部署
  3. [Php] windows下使用composer出现SHA384 is not supported by your openssl extension
  4. C学习笔记(6)--- 共用体,位域深入
  5. C学习笔记(3)---作用域,数组, (少量指针入门)
  6. JDOJ3004 超级楼梯
  7. 【[POI2012]TOU-Tour de Byteotia】
  8. ES2019 的新特性
  9. Luogu P5363 [SDOI2019]移动金币
  10. 【SpringCloud之pigx框架学习之路 】2.部署环境