Day22 面向对象三大特性之封装

1.初识封装

什么是封装

  就是将复杂的丑陋的隐私的细节隐藏到内部,对外提供简单的使用接口

为什么需要封装

  1.为了保证关键数据的安全性

  2.对外部隐藏实现的细节,隔离复杂度

什么时候应该封装

  当有一些数据不希望外界可以直接修改时

  当有一些函数不希望外界使用时

封装的语法:需要封装的属性和方法前加__

 1 # 封装的小例子
 2 class Person:
 3     def __init__(self,name,age,id):
 4         self.name = name
 5         self.age = age
 6         self.__id = id  # 把id封装了
 7 
 8     def say_id(self):
 9         print('我的id是:%s'%self.__id)
10 
11 p1 = Person('sxc',18,11111)
12 # print(p1.id)  # 外界无法访问
13 # print(p1.__id)  # 外界无法访问
14 p1.id = 555
15 print(p1.id)
16 p1.say_id()  # 外界无法修改

 

2.封装方法

封装的方法:需要封装的属性和方法前加__

被封装的内容的特点

  1.外界不能直接访问

  2.内部依然可以使用

模拟电脑开机的例子

 1 # 模拟电脑的开机
 2 class PC:
 3     def __init__(self,brand,price,color):
 4         self.brand = brand
 5         self.price = price
 6         self.color = color
 7 
 8     # def check_device(self):  # 封装前可以直接调用
 9     def __check_device(self):  # 封装后不可以在外部调用,可以在内部调用
10         print("硬件检测1")
11         print("硬件检测2")
12         print("硬件检测3")
13         print("硬件检测4")
14 
15     # def start_services(self):  # 封装前可以直接调用
16     def __start_services(self):  # 封装后不可以在外部调用,可以在内部调用
17         print("启动服务1")
18         print("启动服务2")
19         print("启动服务3")
20         print("启动服务4")
21 
22     # def login(self):  # 封装前可以直接调用
23     def __login(self):  # 封装后不可以在外部调用,可以在内部调用
24         print("login....")
25         print("login....")
26         print("login....")
27 
28     # 定义一个打开电脑的方法,类比电源键
29     def open(self):
30         print('接通电源')
31         self.__check_device()
32         print("载入内核")
33         print("初始化内核")
34         self.__start_services()
35         print("启动GUI")
36         self.__login()
37 
38 p1 = PC('apple',10000,'red')
39 
40 # 比如未封装前要经历三步才能打开电脑
41 # p1.check_device()
42 # p1.start_services()
43 # p1.login()
44 
45 # 封装之后只需经历一步就能打开电脑,就像按电源键一样
46 p1.open()

封装可以控制属性的权限

在python中只要两种权限

  1.公开的,默认就是公开的

  2.私有的,只能由当前类自己使用

 

3.在外界访问被封装的属性

类中的属性虽然被封装起来了,但是还是需要使用的,如果不使用就失去了意义

在外界是通过定义方法类完成对私有属性的修改和访问

对人的id的封装与修改

 1 # 通过类中的方法即函数访问/修改/删除被封装的属性
 2 class Person:
 3     def __init__(self,name,age,id):
 4         self.name = name
 5         self.age = age
 6         self.__id = id  # 把id封装起来
 7 
 8     def get_id(self):  # 获取id的方法
 9         return self.__id
10 
11 
12     def set_id(self,new_id):  # 修改id的方法
13         if type(new_id) == int:
14             str_id = str(new_id)
15             if len(str_id) == 7:
16                 self.__id = new_id
17                 print('新的id是%s'%self.__id)
18                 return
19         print('请输入正确的id')
20 
21     def del_id(self):  # 删除id的方法
22         del self.__id
23         print('删除成功')
24 
25 p1 = Person('sxc',18,1818299)
26 # print(p1.self.__id)  # id已被封装,外界不能直接访问
27 
28 print(p1.get_id())  # 访问被封装的属性
29 p1.set_id('1818211')  # 可以判断修改的属性的对错
30 p1.set_id(1818211)  # 修改被封装的属性
31 p1.del_id()   # 删除被封装的属性
32 # print(p1.get_id())  # 已经删除,报错
33 print(p1.__dict__)  # 结果中没有id属性

在通过函数访问或者修改类内部封装的属性时可以做一些逻辑判断

 

4.property装饰器的使用和封装的原理

通过方法来访问或者修改属性时,我们必须使用调用方法的格式,但这却给使用者带来了麻烦

使用者必须知道哪些属性是普通属性,哪些是私有属性,然后再使用不同的方法调用他们,这对使用者不友好

这时候我们可以使用property装饰器来装饰,可以解决这个问题

装饰器的语法,有三个相关的装饰器

@property  # 用在获取被封装的属性的方法前

@属性名.setter  # 用在修改被封装的属性的方法前

@属性名.deleter  # 用在删除被封装的属性的方法前

注意:属性名是被property装饰的方法的名称,可以是任意的,但为了让使用者能方便的使用,默认使用原来的被封装的属性名,会在类的名称空间的内部创建一个对象,变量名就是函数名称,在使用.setter和.deleter方法时,必须保证使用对象的名称调用方法,所以是属性名.setter

刚才的例子的修改

 1 # property装饰器的使用
 2 class Person:
 3     def __init__(self,name,age,id):
 4         self.name = name
 5         self.age = age
 6         self.__id = id  # 把id封装起来
 7 
 8     @property
 9     def id(self):  # 获取id的方法
10         return self.__id
11 
12     @id.setter
13     def id(self,new_id):  # 修改id的方法
14         if type(new_id) == int:
15             str_id = str(new_id)
16             if len(str_id) == 7:
17                 self.__id = new_id
18                 print('新的id是%s'%self.__id)
19                 return
20         print('请输入正确的id')
21 
22     @id.deleter
23     def id(self):  # 删除id的方法
24         del self.__id
25         print('删除成功')
26 
27 p1 = Person('sxc',18,1818299)
28 
29 print(p1.id)  # 访问被封装的属性
30 p1.id = 1111  # 可以判断修改的属性的对错
31 p1.id = 1818211  # 修改被封装的属性
32 del p1.id   # 删除被封装的属性
33 print(p1.__dict__)  # 结果中没有id属性

 

python实现封装的原理

在加载类的时候,将被封装的属性__双下划替换成了_类名__

 1 # 封装的实现原理
 2 class Person:
 3     def __init__(self,name,age,id):
 4         self.name = name
 5         self.age = age
 6         self.__id = id
 7 
 8 p1 = Person('sxc',18,1818299)
 9 print(p1.__dict__)
10 '''
11 输出结果是{'name': 'sxc', 'age': 18, '_Person__id': 1818299}
12 封装的__id本质是_Person__id,即内部帮我们做了'__id'.replace('__','_Person__')
13 '''
14 print(p1._Person__id)  # 这样就算封装了也能输出

 

5.计算属性

property可以用来实现计算属性

计算属性指的是:属性的值,不能直接获得,需要进行计算才能获得

例如通过正方形的边长求周长和面积

 1 # 计算属性
 2 # 计算一个正方形的周长和面积
 3 class Square:
 4     def __init__(self,side):
 5         self.side = side
 6 
 7     @property
 8     def perimeter(self):
 9         square_perimeter = self.side *4
10         return square_perimeter
11 
12     @property
13     def area(self):
14         area = self.side **2
15         return area
16 
17 s1 = Square(5)
18 print(s1.side)  # 调用属性
19 print(s1.perimeter)  # 可以像属性一样调用他的方法
20 print(s1.area)  # 可以像属性一样调用他的方法

 

6.接口类、抽象类和鸭子类型(了解)

接口是一组功能的集合,但是接口中仅包含功能的名字,不包含具体的实现代码

接口本质是一套协议标准,遵循这个标准的对象就能被调用

接口的目的就是为了提高扩展性.

 1 # 生成一个接口类
 2 class USB:
 3     def open(self):
 4         pass
 5 
 6     def read(self):
 7         pass
 8 
 9     def write(self):
10         pass
11 
12     def close(self):
13         pass
14 
15 # 鼠标这个硬件要继承这个接口类
16 class Mouse(USB):
17     def open(self):
18         print('打开鼠标')
19 
20     def read(self):
21         print('获取光标位置')
22 
23     def write(self):
24         print('不支持该操作')
25 
26     def close(self):
27         print('关闭鼠标')
28 
29 # pc操作
30 def pc(usb_device):
31     usb_device.open()
32     usb_device.read()
33     usb_device.write()
34     usb_device.close()
35 
36 m = Mouse()
37 pc(m)
接口类

 

抽象类

指的是包含抽象方法(没有函数体的方法)的类

作用:可以限制子类必须使用父类中定义的抽象方法

 1 # 抽象类
 2 import abc
 3 class A(metaclass=abc.ABCMeta):
 4     @abc.abstractmethod  # 生成一个限制条件,他的子类必须要有run这个方法
 5     def run(self):
 6         pass
 7 
 8 
 9 class B(A):
10     def run(self):  # 子类拥有父类这个方法
11         print('gogogogo!')
12 
13 b = B()
14 b.run()
抽象类

 

鸭子类型

接口是一套协议规范,明确子类们应该具备哪些功能

抽象类是用于强制要求子类必须按照协议中规定的来实现

然而,python不推崇限制程序员的语法,我们可以设计成鸭子类型,即让多个不同类和对象具备相同的属性和方法,对于使用者可以轻松的使用各种对象.

 

转载于:https://www.cnblogs.com/sxchen/p/11253220.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值