上海 day22 -- 面向对象三大特征---- 封装

目  录

一、封装

什么是封装?

封装就是对外隐藏内部的实现细节,并提供访问的接口。

为什么需要封装?

两个目的:1、保证关键数据的安全性;2、隐藏内部的实现细节,隔离复杂度。

什么时候需要封装?

当有一些数据不需要被外界直接修改时;

当有的函数不希望被外界使用的时候。

二、封装的使用

 封装的语法:

将要封装的属性或方法名称前加双下划线' __ '

代码示例:封装属性

class Person:
    def __init__(self,id,name,age):
        self.__id = id
        self.name = name
        self.age = age

    def show_id(self):
        print(self.__id)
p1 = Person('1234','jason',24)
p1.show_id()  # 1234

print(p1.__id)  # AttributeError: 'Person' object has no attribute '__id' 外界无法访问

代码示例:封装方法

'''
封装方法
'''
class PC:
    def __init__(self,kind,price,color):
        self.kind = kind
        self.price = price
        self.color = color

    def open(self):
        print('接通电源。。')
        self.__check_divice()  # 只能在类的内部调用,也只有在内部才能访问的到
        print('载入内核。。')
        print('初始化内核。。')
        self.__start_services()
        print('启动GUI。。')
        self.__login()

    def __check_divice(self):
        print('检测硬件1')
        print('检测硬件2')
        print('检测硬件3')
        print('检测硬件4')

    def __start_services(self):
        print('开启服务1。。')
        print('开启服务2。。')
        print('开启服务3。。')
        print('开启服务4。。')

    def __login(self):
        print('开始登陆。。')
        print('开始登陆。。')
        print('开始登陆。。')
        print('开始登陆。。')
pc1 = PC('Thinkpad',2000,'red')
pc1.open()
pc1.__check_divice()  # AttributeError: 'PC' object has no attribute '__check_divice'
封装方法

被封装的内容有什么特点?

1、外部不能直接访问

2、内部依然可以调用

控制属性的权限?

在Python中只有两种权限:

1、公开的,默认是公开的

2、私有的,只能在当前类中使用

三、外界访问私有的内容

属性虽然被封装了,但是还是需要使用的,在外界如何访问

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

'''
外部访问私有内容
'''
class Downer:
    def __init__(self, file_name, url, down_size):
        self.file_name = file_name
        self.url = url
        self.__down_size = down_size

    def download(self):
        if self.__down_size >= 1024*1024:
            print('开始下载。。。')
            print('当前缓冲器大小。。%s'%self.__down_size)
        else:
            print('内存炸了!')

    def set_size(self,size):
        if not type(size) == int:
            print('缓冲必须是整型才可以')
        else:
            print('缓冲区修改成功!')
            self.__down_size = size  #  定义方法修改 私有属性 __down_size

    def get_size(self):
        return self.__down_size  #  定义方法访问私有属性  __down_size

d1 = Downer('xunlei','http://www.coming',1024*1024)
d1.download()
# print(d1.get_size())
d1.set_size(1024*2000)  # 2048000  修改私有属性
d1.download()
print(d1.get_size())  # 2048000  访问已经修改的私有属性

这样一来我们可以在外界修改这个关键数据时,做一些限制

property装饰器

通过方法来修改或访问属性,本身没什么问题,但是这给对象的使用者带来了麻烦.

使用必须知道哪些是普通属性,哪些是私有属性,需要使用不同的方式来调用他们

property装饰就是为了使得调用方式一致

有三个相关的装饰器

1.property   该装器用在获取属性的方法上 
2.@key.setter  该装器用在修改属性的方法上 
3.@key.deleter 该装器用在删除属性的方法上 


注意:key是被property装饰的方法的名称 也就是属性的名称 
内部会创建一个对象 变量名称就是函数名称  
所以在使用setter和deleter时 必须保证使用对象的名称取调用方法 
所以是 key.setter

 代码案例:

class A:
    def __init__(self,name,key):
        self.__name = name
        self.__key = key
    @property
    def key(self):
        return self.__key

    @key.setter
    def key(self,size):
        if size > 100:   # 可以设置逻辑判断来选择性设置私有属性
            print('太大了')
        else:
            self.__key = size

    @key.deleter
    def key(self):
        print('你就是删除不了')
        del self.__key

a = A('tank','59')
# print(a.key)  # 这样设置就和普通的对象属性一样,通过 对象名.属性  来访问私有属性
a.key = 99
print(a.key)
a.name = 'jaosn'
print(a.name)

property 可以用来计算属性

计算属性指的是:属性的值,不能直接获得,必须通过计算才能获取

例如:正方形求面积

class Square:

    def __init__(self,width):
        self.width = width
        # self.area = self.width * self.width

    @property
    def area(self):
        return self.width * self.width

s = Square(10)

print(s.area)

 

四、Python实现封装的原理

封装的原理:

  就是在加载类的时候将私有属性的  __属性名      改成了      _类名__属性名

代码示例:

# python实现封装的原理

class A:
    def __init__(self,key):
        self.__key = key

    @property
    def key(self):
        return self.__key
    @key.deleter
    def key(self):
        del self.__key

a1 = A('123')
# del a1.key
# print(a1.key)
# 通过__dict__方法访问a1的名称空间
print(a1.__dict__)  # {'_A__key': '123'} 封装的原理是将 __key 改为 _A__key
print(a1._A__key)  # 123 通过该方法获得 123


# 由以上代码可知,我们访问不到私有属性的原因是,类内部将私有属性的名字改掉了

 五、接口与抽象类

1、接口

什么是接口?

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

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

接口有什么功能?

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

例如电脑提前指定制定一套USB接口协议,只要你遵循该协议,你的设备就可以被电脑使用,不需要关心到底是鼠标还是键盘

案例:

class USB:
    def open(self):
        pass

    def close(self):
        pass

    def  read(self):
        pass

    def write(self):
        pass

class Mouse(USB):
    def open(self):
        print("鼠标开机.....")

    def close(self):
        print("鼠标关机了...")

    def read(self):
        print("获取了光标位置....")

    def write(self):
        print("鼠标不支持写入....")


def pc(usb_device):
    usb_device.open()
    usb_device.read()
    usb_device.write()
    usb_device.close()

m = Mouse()
# 将鼠标传给电脑
pc(m)

class KeyBoard(USB):
    def open(self):
        print("键盘开机.....")

    def close(self):
        print("键盘关机了...")

    def read(self):
        print("获取了按键字符....")

    def write(self):
        print("可以写入灯光颜色....")

# 来了一个键盘对象
k = KeyBoard()
pc(k)
View Code

在上述案例中,PC的代码一旦完成,后期无论什么样的设备 只要遵循了USB接口协议,都能够被电脑所调用

接口主要是方便了对象的使用者,降低使用者的 学习难度,只要学习一套使用方法,就可以以不变应万变

问题?——》引出抽象类

如果子类没有按照你的协议来设计,也没办法限制他,将导致代码无法运行

2、抽象类

什么是抽象类?

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

抽象类有什么作用?

可以限制子类必须具备父类中定义的抽象方法

abc模块的使用:

"""
abc 不是随意取的 而是单词的缩写
abstract class
翻译为抽象类
抽象类的定义 :
类中包含 没有函数体的方法


"""
import abc

class AClass(metaclass=abc.ABCMeta):

    @abc.abstractmethod
    def run(self):
        pass
    @abc.abstractmethod
    def run1(self):
        pass


class B(AClass):

    def run(self):
        print("runrunrurn...")

b = B()

最后总结:鸭子类型

python一般不会限制你必须怎么写,作为一个优秀的程序员,就应该自觉遵守相关协议

所以有了鸭子类型这么一说:

如果这个对象长得像鸭子,走路像鸭子,那就他是鸭子—— 即这个对象具备父类定义的属性和方法

你只要保证你的类按照相关的协议类编写,也可以达到提高扩展性的目的

案例:

class Mouse:
    def open(self):
        print("鼠标开机.....")

    def close(self):
        print("鼠标关机了...")

    def read(self):
        print("获取了光标位置....")

    def write(self):
        print("鼠标不支持写入....")



def pc(usb_device):
    usb_device.open()
    usb_device.read()
    usb_device.write()
    usb_device.close()

m = Mouse()
# 将鼠标传给电脑
pc(m)

class KeyBoard:
    def open(self):
        print("键盘开机.....")

    def close(self):
        print("键盘关机了...")
        
    def read(self):
        print("获取了按键字符....")
        
    def write(self):
        print("可以写入灯光颜色....")

        
# 来了一个键盘对象
k = KeyBoard()
pc(k)

class UDisk:
    def open(self):
        print("U盘启动了...")

    def close(self):
        print("U盘关闭了...")

    def read(self):
        print("读出数据")

    def write(self):
        print("写入数据")

u = UDisk()
pc(u)
鸭子类型

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

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

然而,python不推崇限制你的语法, 我们可以设计成鸭子类型,既让多个不同类对象具备相同的属性和方法

对于使用者而言,就可以以不变应万变,轻松的使用各种对象

 

 

 

 

 

原文地址:https://www.cnblogs.com/qinsungui921112/p/11252060.html