面向对象的编程语言在写大型程序的的时候,往往比面向过程的语言用起来更方便,安全。其中原因之一在于:类机制。
类,对众多的数据进行分类,封装,让一个数据对象成为一个完整的个体,贴近现实生活,高度抽象化。但是,python对类的封装并不好,因为所有的属性和方法都是公开的,你可以随意访问或者写入,你可以在类的外部对类的属性进行修改,甚至添加属性。这的确让人感到不安。
下面就来总结一下学习后的解决方案。
1,使用2个下划线前缀隐藏属性或者方法。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
|
__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.创建可管理的属性。
有时候我们需要对属性的写入做额外的检查,对不合法的值拒绝写入,引发异常。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
|
#!/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....当然是可以的,但是,它“暴露”了,我们不想让它在外部可用,还是应该
加 __ 将它隐藏,防止意外修改。
有时候,你确定某个类不会涉及到继承,那么,就可以将上述的双下划线改写为单下滑线,虽然不会达到隐藏的作用,但是:一方面,这样不会引发名称重整机制,
避免小题大做,另一面,用一个下划线开头,可以提醒使用者,这个属性不应该直接使用。那么,这就靠自觉了。
一个实例对象可以在外部随意添加属性。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
|
#!/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对象数据的读写权限就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持服务器之家。