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


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

     22

  • 相关阅读:
    观察者模式-Observer
    @Resource、@Autowired、@Qualifier的注解注入及区别
    Java垃圾回收(GC)机制详解
    java什么时候进行垃圾回收,垃圾回收的执行流程
    Log4J.xml配置详解
    springMVC配置拦截器、过滤器、前端控制器时遇到的问题总结
    基于zookeeper实现分布式锁
    数据库索引原理及优化
    数据分析——CentOS7配置时间和ntp
    solr——zookeeper部署
  • 原文地址:https://www.cnblogs.com/sxchen/p/11253220.html
Copyright © 2020-2023  润新知