浅谈python对象数据的读写权限


Posted in Python onSeptember 12, 2016

面向对象的编程语言在写大型程序的的时候,往往比面向过程的语言用起来更方便,安全。其中原因之一在于:类机制。

类,对众多的数据进行分类,封装,让一个数据对象成为一个完整的个体,贴近现实生活,高度抽象化。但是,python对类的封装并不好,因为所有的属性和方法都是公开的,你可以随意访问或者写入,你可以在类的外部对类的属性进行修改,甚至添加属性。这的确让人感到不安。

下面就来总结一下学习后的解决方案。

1,使用2个下划线前缀隐藏属性或者方法。

__xxx

#!/usr/bin/python3
#-*- coding:utf-8 -*-


class Student:
  def __init__(self,name,score):
    self.name = name
    self.__score = score #将score隐藏起来,使之仅在类内部可用。

  def __show(self):    #一个隐藏的方法,同样只在内部可用
    print(self.name,self.__score)#使用被隐藏的属性__score
    
  def Show(self):
    self.__show()    #注意被隐藏方法的调用方式。


  
def main():
  he = Student('Bob',95)
  he.Show()       #显示:Bob 95
  #print(he.__score)   #AttributeError: 'Student' object has no attribute '__score'
  #he.__show()      #AttributeError: 'Student' object has no attribute '__show'

  #隐藏属性真的被隐藏了吗?其实仍然可使用,使用格式 obj._className__attributeName
  #但是仅仅作为了解,不建议使用隐藏属性。
  print(he._Student__show())  #显示:Bob 95
  print(he._Student__score)   # 显示: 95
  
  
  

if __name__=="__main__":
  main()

双下划线对类属性的影响:

1. 使属性只用于本类的内部,外部以及子类都不可直接读取修改。

2. 使用 _ _ 的类的属性,在实现时会被更改名称,如类中的__age   最后会变为_A__age (名称重整),这个好处是:通常用于涉及到继承的父类中使用。这样避免被子类属性覆盖。

2.创建可管理的属性。

有时候我们需要对属性的写入做额外的检查,对不合法的值拒绝写入,引发异常。

#!/usr/bin/python3
#-*- coding:utf-8 -*-


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

  @property        #实现属性的读取方法,读取实例的score值时,就会调用这个函数
  def score(self):
    return self.__score

  
  @score.setter     #实现属性写入方法,写入实例的score属性时,调用这个函数
  def score(self,newVal):
    if not isinstance(newVal,(int,float)):
      raise TypeError('score value must be a number')
    if newVal>100 or newVal<0:
      raise ValueError('score value must between 0 and 100')

    self.__score = newVal

  

  
def main():
  he = Student('Bob',95)
  he.score = 100   #重新写入 

  
  print(he.score)  #读取   
    
  

if __name__=="__main__":
  main()

我们可以发现:  self.__score是 属性值 的真正存储的地方,而self.score是函数(只不过它用起来像一个属性),它是获取和写入属性值的方法。

初始化的时候也会调用socre.setter 装饰的函数,因为__init__()函数下出现了self.score的调用

既然self.__score仅仅用来引用属性的值,可不可以用别的命名呢?如saveScore....当然是可以的,但是,它“暴露”了,我们不想让它在外部可用,还是应该

加 __ 将它隐藏,防止意外修改。

有时候,你确定某个类不会涉及到继承,那么,就可以将上述的双下划线改写为单下滑线,虽然不会达到隐藏的作用,但是:一方面,这样不会引发名称重整机制,

避免小题大做,另一面,用一个下划线开头,可以提醒使用者,这个属性不应该直接使用。那么,这就靠自觉了。

一个实例对象可以在外部随意添加属性。

#!/usr/bin/python3
#-*- coding:utf-8 -*-


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

 

  
def main():
  he = Student('Bob',95)
  he.age = 19
  print(he.age)
  

if __name__=="__main__":
  main()

使用__slots__



#!/usr/bin/python3
#-*- coding:utf-8 -*-


class Student:
  __slots__ = ('name','score') #将属性名以字符串形式加入元组
  def __init__(self,name,score):
    self.name = name
    self.score = score 

 

  
def main():
  he = Student('Bob',95)
  he.age = 19  #AttributeError: 'Student' object has no attribute 'age'
  print(he.age)
  

if __name__=="__main__":
  main()

这样,对象的属性就限定在类的内部了。

但是__slots__不能被继承。而且,__slots__的设计本意并不是上面的用法,而是创建大量(万计)对象时对内存占用进行优化。

总结:

写着写着,我发觉上面的技巧意义不大。类的设计是程序员本人,使用者也是本人,那么,对象属性的

读和写就应该自己把握,类设计时本身不需要太多的保护代码,否则会很臃肿,而且效率降低。保护措施应该发生在类的外部,让类对象接受到的数据永远是合法的,这样会更加轻巧灵活。这是我的感受。

以上这篇浅谈python对象数据的读写权限就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持三水点靠木。

Python 相关文章推荐
python thread 并发且顺序运行示例
Apr 09 Python
Python中lambda的用法及其与def的区别解析
Jul 28 Python
分享Python开发中要注意的十个小贴士
Aug 30 Python
Python实用技巧之利用元组代替字典并为元组元素命名
Jul 11 Python
Python实现FTP弱口令扫描器的方法示例
Jan 31 Python
PyQt打开保存对话框的方法和使用详解
Feb 27 Python
python使用MQTT给硬件传输图片的实现方法
May 05 Python
pyqt5 实现工具栏文字图片同时显示
Jun 13 Python
tensorflow之自定义神经网络层实例
Feb 07 Python
用python制作个音乐下载器
Jan 30 Python
pytorch加载预训练模型与自己模型不匹配的解决方案
May 13 Python
仅用几行Python代码就能复制她的U盘文件?
Jun 26 Python
python获取list下标及其值的简单方法
Sep 12 #Python
Python循环语句中else的用法总结
Sep 11 #Python
python字典键值对的添加和遍历方法
Sep 11 #Python
解决Python 遍历字典时删除元素报异常的问题
Sep 11 #Python
完美解决python遍历删除字典里值为空的元素报错问题
Sep 11 #Python
python 循环遍历字典元素的简单方法
Sep 11 #Python
遍历python字典几种方法总结(推荐)
Sep 11 #Python
You might like
Php 构造函数construct的前下划线是双的_
2009/12/08 PHP
php设计模式之观察者模式的应用详解
2013/05/21 PHP
php读取文件内容的三种可行方法示例介绍
2014/02/08 PHP
php使用COPY函数更新配置文件的方法
2015/06/18 PHP
服务器迁移php版本不同可能诱发的问题
2015/12/22 PHP
非常有用的9个PHP代码片段
2016/04/06 PHP
PHP微信开发之查询微信精选文章
2016/06/23 PHP
js实例属性和原型属性示例详解
2014/11/23 Javascript
JavaScript中匿名函数用法实例
2015/03/23 Javascript
JQuery中Text方法用法实例分析
2015/05/18 Javascript
JQuery.Ajax()的data参数类型实例详解
2015/11/20 Javascript
谈谈javascript中使用连等赋值操作带来的问题
2015/11/26 Javascript
BootStrap智能表单实战系列(八)表单配置json详解
2016/06/13 Javascript
JS本地刷新返回上一页代码
2016/07/25 Javascript
详解使用grunt完成requirejs的合并压缩和js文件的版本控制
2017/03/02 Javascript
微信小程序 引入es6 promise
2017/04/12 Javascript
Javascript中toFixed计算错误(依赖银行家舍入法的缺陷)解决方法
2017/08/22 Javascript
JS实现不用中间变量temp 实现两个变量值得交换方法
2018/02/04 Javascript
vue 中filter的多种用法
2018/04/26 Javascript
关于Vue组件库开发详析
2018/07/01 Javascript
微信小程序使用wxParse解析html的方法示例
2019/01/17 Javascript
微信小程序实现炫酷的弹出式菜单特效
2019/01/28 Javascript
mpvue+vant app搭建微信小程序的方法步骤
2019/02/11 Javascript
Nginx设置为Node.js的前端服务器方法总结
2019/03/27 Javascript
Node.js API详解之 dgram模块用法实例分析
2020/06/05 Javascript
Python实现基于二叉树存储结构的堆排序算法示例
2017/12/08 Python
Python对象转换为json的方法步骤
2019/04/25 Python
Pytest单元测试框架如何实现参数化
2020/09/05 Python
香港最大的洋酒零售连锁店:屈臣氏酒窖(Watson’s Wine)
2018/12/10 全球购物
阿里巴巴英国:Alibaba英国
2019/12/11 全球购物
教师自荐信范文
2013/12/09 职场文书
考试诚信承诺书
2014/05/23 职场文书
学生安全责任协议书
2016/03/22 职场文书
在CSS中使用when/else的方法
2022/01/18 HTML / CSS
Python采集股票数据并制作可视化柱状图
2022/04/04 Python
Redis基本数据类型Zset有序集合常用操作
2022/06/01 Redis