Python面向对象三要素-封装(Encapsulation)

                                      作者:尹正杰

版权声明:原创作品,谢绝转载!否则将追究法律责任。

 

 

一.封装概述

  将数据和操作组织到类中,即属性和方法 
  
  将数据隐藏起来,给使用者提供操作(方法)。使用者通过操作就可以获取或者修改数据。getter和setter。 
  
  通过访问控制,暴露适当的数据和操作给用户,该隐藏的隐藏起来,例如保护成员或私有成员。

 

二.类属性的访问控制 

1>.抛出问题 

 1 #!/usr/bin/env python
 2 #_*_conding:utf-8_*_
 3 #@author :yinzhengjie
 4 #blog:http://www.cnblogs.com/yinzhengjie
 5 
 6 
 7 class Person:
 8     def __init__(self,name,age=18):
 9         self.name = name
10         self.age = age
11 
12     def growup(self,i=1):
13          if i > 0 and i < 150:  #控制逻辑
14              self.age += i
15 
16 
17 p1 = Person("jason")
18 print(p1.age)
19 
20 p1.growup(20)           #在我们控制逻辑的范围内
21 print(p1.age)
22 
23 p1.age = 9999           #直接修改对象的属性,超过了范围,并绕过了咱们控制逻辑,是不是很操蛋?Python提供了私有属性可以解决这个问题。
24 print(p1.age)
25 
26 
27 
28 #以上代码输出结果如下:
29 18
30 38
31 9999

2>.私有(Private)属性

 1 #!/usr/bin/env python
 2 #_*_conding:utf-8_*_
 3 #@author :yinzhengjie
 4 #blog:http://www.cnblogs.com/yinzhengjie
 5 
 6 
 7 class Person:
 8     def __init__(self,name,age=18):
 9         self.name = name
10         """
11             私有变量的本质: 类定义的时候,如果声明一个实例变量的时候,使用双下划线,Python解释器会将其改名,转换名称为"_类名__变量名"的名称,所以用原来的名字访问不到了。
12         """
13         self.__age = age            #使用双下划线开头的属性名,就是私有属性
14 
15     def growup(self,i=1):
16          if i > 0 and i < 150:      #控制逻辑
17              self.__age += i
18 
19     def getage(self):               #我们只对外提供访问"__age"的方法
20         return self.__age
21 
22 p1 = Person("jason")
23 print(p1.getage())
24 print(p1.__dict__)
25 
26 p1.growup(120)
27 print(p1.getage())
28 
29 print(Person.__dict__)
30 print(p1.__dict__)
31 
32 #p1.__age == 9999                   #我们发现现在无法访问到"__age"这个属性啦,会抛出"AttributeError"异常
33 p1._Person__age = 9999              #既然我们知道了私有变量的新名称,就可以直接从外部访问到,并修改它。因此尽管是私有属性我们依旧是可以对其进行更改,但建议大家不要去修改,因为这样就违背了私有变量但属性啦,但你如果一定要改的话你得知道去哪改哟。
34 print(p1.getage())
35 print(p1.__dict__)
36 
37 
38 
39 #以上代码输出结果如下:
40 18
41 {'name': 'jason', '_Person__age': 18}
42 138
43 {'__module__': '__main__', '__init__': <function Person.__init__ at 0x10075f950>, 'growup': <function Person.growup at 0x10075fae8>, 'getage': <function Person.getage at 0x10075fb70>, '__dict__': <attribute '__dict__' of 'Person' objects>, '__weakref__': <attribute '__weakref__' of 'Person' objects>, '__doc__': None}
44 {'name': 'jason', '_Person__age': 138}
45 9999
46 {'name': 'jason', '_Person__age': 9999}

3>.保护(protected)属性

 1 #!/usr/bin/env python
 2 #_*_conding:utf-8_*_
 3 #@author :yinzhengjie
 4 #blog:http://www.cnblogs.com/yinzhengjie
 5 
 6 
 7 class Person:
 8     def __init__(self,name,age=18):
 9         self.name = name
10         """
11             在变量名前使用一个下划线,称为保护变量。
12             可以看出,这个_age属性根本就没有改变名称,和普通的属性一样,解释器不做任何特殊处理。 
13             这只是开发者共同的约定,看见这种变量,就如同私有变量,不要直接使用。
14         """
15         self._age = age
16 
17 
18 p1 = Person("jason")
19 
20 print(p1._age)
21 print(p1.__dict__)              #
22 
23 
24 
25 #以上代码输出结果如下:
26 18
27 {'name': 'jason', '_age': 18}

4>.私有方法

 1 #!/usr/bin/env python
 2 #_*_conding:utf-8_*_
 3 #@author :yinzhengjie
 4 #blog:http://www.cnblogs.com/yinzhengjie
 5 
 6 
 7 """
 8 私有方法的本质
 9     单下划线的方法只是开发者之间的约定,解释器不做任何改变。
10     双下划线的方法,是私有方法,解释器会改名,改名策略和私有变量相同, 即"_类名__方法名" 。
11     方法变量都在类的 __dict__ 中可以找到。
12 """
13 class Person:
14     def __init__(self, name, age=18):
15         self.name = name
16         self._age = age
17 
18     """
19         参照保护变量、私有变量,使用单下划线、双下划线命名方法。
20     """
21     def _getname(self):
22         return self.name
23 
24     def __getage(self):
25         return self._age
26 
27 
28 jason = Person('Jason')
29 print(jason._getname())  # 没改名
30 #print(jason.__getage()) # 无此属性
31 print(jason.__dict__)
32 print(jason.__class__.__dict__)
33 print(jason._Person__getage()) # 改名了
34 
35 
36 
37 #以上代码执行结果如下:
38 Jason
39 {'name': 'Jason', '_age': 18}
40 {'__module__': '__main__', '__init__': <function Person.__init__ at 0x10215f950>, '_getname': <function Person._getname at 0x10215fae8>, '_Person__getage': <function Person.__getage at 0x10215fb70>, '__dict__': <attribute '__dict__' of 'Person' objects>, '__weakref__': <attribute '__weakref__' of 'Person' objects>, '__doc__': None}
41 18

5>.私有成员的总结

  在Python中使用 _单下划线 或者 __ 双下划线来标识一个成员被保护或者被私有化隐藏起来。 
 
  但是,不管使用什么样的访问控制,都不能真正的阻止用户修改类的成员。Python中没有绝对的安全的保护成员或者私有成员。 

  因此,前导的下划线只是一种警告或者提醒,请遵守这个约定。除非真有必要,不要修改或者使用保护成员或者私有成员,更不要修改它们。

 

三.补丁

  可以通过修改或者替换类的成员。使用者调用的方式没有改变,但是,类提供的功能可能已经改变了。

  猴子补丁(Monkey Patch):
    在运行时,对属性、方法、函数等进行动态替换。
    其目的往往是为了通过替换、修改来增强、扩展原有代码的能力。
    黑魔法,慎用。
 1 #!/usr/bin/env python
 2 #_*_conding:utf-8_*_
 3 #@author :yinzhengjie
 4 #blog:http://www.cnblogs.com/yinzhengjie
 5 
 6 class Person:
 7     def get_score(self):
 8         #模拟下面的字典是从数据库拿的某个学生成绩(基本是及格的不多呀)。
 9         ret = {"English":37,"Chinese":66,"History":52}
10         return ret
test2.py

相关文章:

  • 2022-12-23
  • 2022-01-15
  • 2021-12-06
  • 2021-06-12
  • 2022-02-13
  • 2019-12-03
  • 2022-03-01
  • 2022-01-04
猜你喜欢
  • 2021-05-20
  • 2022-12-23
  • 2022-12-23
  • 2021-09-17
  • 2021-05-23
  • 2022-12-23
相关资源
相似解决方案