面向对象之封装

一:封装

【1】基础概念

(1)什么是封装:

  (1)字面意思是将什么封存在什么里面 达到隐藏的效果

   例如:将电脑里的硬件封装在机盒中 

  (2)在程序中是将复杂的 丑陋的的细节封装在内部 对外部提供简易的接口 供人们使用

    例如:电脑开机需要调度大量的硬件 但是这些硬件我们本身根本不需要考虑 直接使用开机键这个简单的接口就行

(2)封装的好处:

  (1)保证数据的安全性:

  (2)对外部隔离内部细节 降低复杂度

(3)封装使用场景:

  (1)一些数据不希望外界直接修改的时

    例如:数据库中的个人信息如果外部访问可以随时修改 会导致数据随时被篡改的危险

  (2)一些函数不希望给外部直接使用的时候

    例如:电脑开机的时候 加载操作系统 这些方式本身人为不需要管 因为只需要定义好 由硬件直接操作就可以 人为不需要干预

(4)封装的使用方式:

  (1):对属性进行封装

例如:

class Person:
    def __init__(self,name,id_card):
        self.name = name
        self.__id_card = id_card

    def show_id_cart(self):
        return print(self.__id_card)


p = Person('SR',123456789)

print(p.id_card) # 123456789原始身份证信息

p.id_card = 987654321

print(p.id_card) # 987654321 身份证被修改

# 对数据进行封装
p.show_id_cart()  # 123456789原始函数
对属性进行数据封装

PS:上述通过对属性进行封装 提高数据的安全性

  (2)对方法进行封装

例如:

# class Person:
#     def __init__(self,name,id_card):
#         self.name = name
#         self.__id_card = id_card
#
#     def show_id_cart(self):
#         return print(self.__id_card)
#
#
# p = Person('SR',123456789)
#
# print(p.id_card) # 123456789原始身份证信息
#
# p.id_card = 987654321
#
# print(p.id_card) # 987654321 身份证被修改
#
# # 对数据进行封装
# p.show_id_cart()  # 123456789原始函数



class PC:
    def __init__(self,kind,price,):
        self.kind = kind
        self.price = price

    def open(self):
            print("接通电源")
            self.__check_device()
            print("载入内核")
            self.__start_services()
            print("初始化内核")
            print("启动GUI")
            self.__login()

    # 这些函数人们都是不需要使用的 进行封装
    # 假如不开机 直接调用这些函数 也不合适
    def __check_device(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("login....")
        print("login....")


p = PC('apple',18888)

p.open() # 正常启动

p.__login()  # 报错
对方法进行数据封装

PS:

(1)对方法进行封装 防止不必要的方法被外界调用

(2)将不必须要的方法封装 只需要给外部提供一个可以访问的接口即可 降低复杂度

(5)封装特点:

  (1)内部可以访问内部被封装的函数或者属性

  (2)外部不可以直接访问内部被封装的函数或者属性

【2】封装扩展:

(1)权限问题

  (1)默认属于公有的 大家都可以使用

  (2)被封装之后即属于私有的 只能由当前类自己使用 外部不能直接调用

(2)如何访问被封装的属性:

(1)产生背景

  (1)如果内部属性与方法被进行封装 导致外部不能直接读取 那么这些属性存在也没有直接意义

    例如:上述用户不能直接读取直接的身份证,电脑使用开机键 也不能去取内部加载程序 

  (2)通过特殊的方法进行访问内部被封装属性或者方法

例如:

# # class Person:
# #     def __init__(self,name,id_card):
# #         self.name = name
# #         self.__id_card = id_card
# #
# #     def show_id_cart(self):
# #         return print(self.__id_card)
# #
# #
# # p = Person('SR',123456789)
# #
# # print(p.id_card) # 123456789原始身份证信息
# #
# # p.id_card = 987654321
# #
# # print(p.id_card) # 987654321 身份证被修改
# #
# # # 对数据进行封装
# # p.show_id_cart()  # 123456789原始函数
#
#
#
# class PC:
#     def __init__(self,kind,price,):
#         self.kind = kind
#         self.price = price
#
#     def open(self):
#             print("接通电源")
#             self.__check_device()
#             print("载入内核")
#             self.__start_services()
#             print("初始化内核")
#             print("启动GUI")
#             self.__login()
#
#     # 这些函数人们都是不需要使用的 进行封装
#     # 假如不开机 直接调用这些函数 也不合适
#     def __check_device(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("login....")
#         print("login....")
#
#
# p = PC('apple',18888)
#
# p.open() # 正常启动
#
# p.__login()  # 报错


class Downloader:
    def __init__(self,filename,url,buffer_size):
        self.filename = filename
        self.url = url
        self.__buffer_size= buffer_size

    def start_download(self):
        if self.__buffer_size <= 1024*1024:
            print('开始下载')
            # 查看当前缓存大小
            print('当前缓存大小',self.__buffer_size)
        else:
            print('丢雷楼某 顶你个肺啊 内存太大了 想给电脑搞崩溃啊')

    # 定义一个新的方法
    def set_buffer_size(self,size):

        # 添加额外逻辑判断 只允许整形
        if not type(size) == int:
            print('丢雷楼某 顶你个肺啊 不知道输入数字啊')
        else:
            # 定义下载数据 类内部可以访问内部封装属性
            self.__buffer_size = size


# 只允许每次下载1M
d = Downloader('新闻联播','百度',1024*1024)
# d.start_download()

# 自己私定义下载属性 因此需要对内部数据进行封装
# d.buffer_size = 1024*1024*10
# d.start_download()

'''
1:虽然现在通过封装导致内部属性不能被随便修改
2:但是却将内部属性给限制死了 假如电脑配置比较差 每次只能读取0.5M的 
3:现在却只能下载1m 
'''
# 外部调用新的函数
d.set_buffer_size(1024*1024/2)
d.start_download() #  524288.0 下载大小

'''
但是这样也没有意义  封装没有必要了 不如直接赋值为某个值
但是现在这个属于函数 可以添加额外的逻辑 或者属性
例如:加入用户上传字符串 现在不合理 我通过现在用户只能上传数字

'''
d.set_buffer_size('132132') # 丢雷楼某 顶你个肺啊 不知道输入数字啊

d.set_buffer_size(1024*512)
d.start_download() #  524288
定义方法类对内部函数进行属性修改

PS:内部通过创建新的函数 主要可以进行一些逻辑上的判断

(3)装饰器

  (1)property:

    (1)在上述中因为被封装成私有属性 私有属性与公有属性调用方式不同

    (2)用户需要知道那个是私有 那个是公有的 为了统一调用方式 需要进行装饰

例如:

class User_info:
    def __init__(self,name,id_cart):
        self.name = name
        # 为了防止内部数据被外部随便修改 进行封装
        self.__id_cart = id_cart

    @property
    def id(self):
        return self.__id_cart

user = User_info('SR',12345678)

# 被装饰之前
print(user.id()) # 12345678 被装饰之前

# 装饰后
print(user.id) # 12345678
property属性

  (2)setter

    (1)可以将私有属性按照普通属性的形式 进行修

例如:

class User_info:
    def __init__(self,name,id_cart):
        self.name = name
        # 为了防止内部数据被外部随便修改 进行封装
        self.__id_cart = id_cart

    @property
    def id(self):
        return self.__id_cart

    @id.setter
    def id(self,new_id):
        # 添加条件限制
        if type(new_id) == int:
            self.__id_cart = new_id
            # 查看该函数是否被行
            print('代码正在执行') # 代码正在执行
            print(self.__id_cart) # 987654321
        else:
            print('丢雷楼某 顶你个肺啊 能不能好好输入啊!')


user = User_info('SR',12345678)

user.id = 987654321

print(user.id) # 987654321

user.id = 'SR'
print(user.id) # 丢雷楼某 顶你个肺啊 能不能好好输入啊!
setter属性

  (3)delete

class User_info:
    def __init__(self,name,id_cart):
        self.name = name
        # 为了防止内部数据被外部随便修改 进行封装
        self.__id_cart = id_cart

    @property
    def id(self):
        return self.__id_cart

    @id.setter
    def id(self,new_id):
        # 添加条件限制
        if type(new_id) == int:
            self.__id_cart = new_id
            # 查看该函数是否被行
            print('代码正在执行') # 代码正在执行
            print(self.__id_cart) # 987654321
        else:
            print('丢雷楼某 顶你个肺啊 能不能好好输入啊!')
    @id.deleter
    def id(self):
        print('删除属性')

        # 删除属性
        del self.__id_cart

user = User_info('SR',12345678)

del user.id
#此时代码并没有被真正删除
print(user.id) # 删除属性
delete 属性

(4)封装的实现原理:

  (1)就是在加载类的时候将__替换成了 _类名__

例如:

class Number:
    def __init__(self,number):
        self.__number = number

    @property
    def number(self):
        return self.__number


n = Number(123)

print(n.__dict__) # {'_Number__number': 123}

print(n._Number__number) # 123

(5)计算属性:

  (1)属性的值 不能直接获取 必须通过计算获取

例如:

class Spure:
    def __init__(self,len):
        self.len = len

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


s = Spure(10)
s.len = 20
print(s.area) # 400

s.len = 4
print(s.area)  # 16

(6)接口:

  (1)接口是一组功能的集合 但是接口只包含功能的名字 不包含功能代码

  (2)其实本质就是一套标准协议 遵循这个标准协议的代码 就能被调用

  (3)如果子类没有按照规范进行编写 也不能阻止代码运行

(2)抽象类

  (1)没有具体功能(函数体代码)的类

  (2)限制子类中必须定义的方法

(3)鸭子类型

  (1)python具体不会限制人们该怎么写代码

  (2)如果这个对象长的像鸭子 走路像鸭子就是鸭子类型

  (3)即你只要按照相关协议来编写代码 也可以达到提高扩展性的目的

原文地址:https://www.cnblogs.com/SR-Program/p/11252818.html