• day 25


    封装

    对外部隐藏内部的属性,以及实现细节 , 给外部提供使用的接口

    注意:封装有隐藏的意思,但不是单纯的隐藏

    学习封装的目的.就是为了能够限制外界对内部数据的访问

    python中属性的权限分为两种

    1.公开的

    没有任何限制 谁都能访问

    2.私有的

    只有当前类本身能够访问

    默认为公共的

     

    如何封装

    为什么要封装 why

    1.提高安全性

    封装属性

    2.隔离复杂度

    封装方法

    在一个类中分为属性和方法两种数据

    1.  封装属性

    class Student:
    
        def __init__(self,name,age,gender,id_card):
            self.name = name
            self.age = age
            self.gender = gender
            self.__id_card = id_card   #添加--来将类中的属性隐藏,不对外界直接开放,在程序中提供查看和调用的接口
    
        def show_id_card(self):
            # 可以在这里添加额外的任何逻辑代码 来限制外部的访问
            # 提供给外界调用查看属性的接口
            #在类的内部 可以访问
            print(self.__id_card)

    可以对私有属性的访问进行修改

    对封装的属性进行修改操作的函数中  get 表示访问器, 使用set 表示设置器

    class Student:
        def __init__(self,name,age,gender,id_card):
            self.name = name
            self.age = age
            self.gender = gender
            self.__id_card = id_card
    
        # 访问被封装的属性  称之为访问器
        def get_id_card(self,pwd):
            # 可以在这里添加额外的任何逻辑代码 来限制外部的访问  例如加入访问密码判断的限制
            # 在类的内部 可以访问
            if pwd =="123":
                return self.__id_card
            raise Exception("密码错误!")
    
    
        # 修改被封装的属性   称之为设置器
        def set_id_crad(self,new_id):
            # 身份证必须是字符串类型
            # 长度必须是18位
            if isinstance(new_id,str) and len(new_id) == 18:
                self.__id_card = new_id
            else:
                raise Exception("身份证号码 必须是字符串 且长度必须为18!")

    什么样的方法应该被封装起来

    一个为内部提供支持的方法,不应该让外界直接访问,那就封装起来 ,如下例中的 银行银行系统中的用户各类信息,如

    用户密码,用户余额等个人信息。.

    class ATM:
    
        def withdraw(self):
            self.__user_auth()
            self.__input_money()
            self.__save_record()
            # 输入账号和密码
            # 显示余额
            # 输入取款金额
            # 保存记录
     以下函数接口为提供给外界调用查看的路径,封装的作用并不是将信息锁死,可以作为起保护作用来看待封装的作用
        def __user_auth(self):
            print("请输入账号密码....")
    
        def __input_money(self):
            print("余额为100000000,请输入取款金额!")
    
        def  __save_record(self):
            print("记录流水....")

    封装的原理和接口的原理类似通过变形的方式来实现封装

    实现方式上在名称前面带有双下划线的变量名前面加上-类名。

    变形后可以直接访问被隐藏的属性,但是一般不这样操作,可以但没有必要。

    变形只会在类的定义阶段发生一次,之后在添加的双划线开头的属性就只是普通属性了。

    class Person:
        def __init__(self,name,age,id_card):
            self.name = name
            self.age = age
            self.__id_card = id_card
    
        def get_id_card(self):
            return self.__id_card
    
    p = Person("rose",20,"321123123123123123")
    print(p.name)
    
    
    p.__id_card = "321"
    print(p.__dict__)
    #打印结果:{'name': 'rose', 'age': 20, '_Person__id_card': '321123123123123123', '__id_card': '321'}
    可以看出只是属于新添加的一个对象属性。
    print(p._Person__id_card) p.__gender = "man" print(p.__dict__)
    #和上一个打印结果相同,后加入只是被当作普通属性来进行添加{'name': 'rose', 'age': 20, '_Person__id_card': '321123123123123123', '__id_card': '321', '__gender': 'man'}

    当属性被隐藏之后访问方式就和访问普通属性有些不同,需要用定义的对象点出接口后在加个括号有些麻烦。

    这里使用装饰器来实现访问和访问普通属性一致  property 

    class Teacher:
        def __init__(self,name,age,salary):
            self.name = name
            self.age = age
            self.__salary = salary
    
        @property  # getter   # 用于访问私有属性的值   也可以访问普通属性
        def salary(self):
            return self.__salary
    
        @salary.setter   # 用来设置私有属性的值  也可以设置普通属性
        def salary(self,new_salary):
            self.__salary = new_salary
    
        @salary.deleter # 用来设置私有属性的值  也可以删除普通属性
        def salary(self):
            # print("can not delete salary!")
            del self.__dict__["_Teacher__salary"]

    property的另一种使用场景 计算属性

    计算属性是指他的值是通过计算动态得来的,并不是一成不变的。

    这里例举出一个通过动态计算得出的体质指数

    class Person:
        def __init__(self,name,height,weight):
            self.name = name
            self.height = height
            self.weight = weight
            # self.BMI = weight / (height ** 2)
    
        @property      
        def BMI(self):
            return self.weight / (self.height ** 2)      接口处添加计算方式,这样当用户输入自己的真实身高体重时就会通过这个
    接口,得出自己的真实的体重状况 @BMI.setter
    def BMI(self,new_BMI): print("BMI 不支持自定义.....") p = Person("egon",1.7,80) print(p.BMI) p.BMI = 10

    多态 :

    多态不是一个具体的技术 或代码

    指的是 多个不同类型对象 可以响应同一个方法 ,产生不同结果

    可以和鸭子类型画上等号,多态的理想状态就是鸭子形态,不理想状态就是接口。

    class Cat():
        def bark(self):
            print("喵喵喵")
        def run(self):
            print("四条腿跑!")
        def sleep(self):
            print("趴着睡!")
            
    class Pig():
        def bark(self):
            print("哼哼哼!")
        def run(self):
            print("四条腿跑!")
        def sleep(self):
            print("侧躺着睡!")
    
    # 一个用来管理动物的方法   只要你传入是一个动物 我就按照动物的标准来使用 完全不用考虑你具体是什么类型
    def management_animal(animal):
        print("==================正在溜%s=============" % animal.__class__.__name__)
        animal.bark()
        animal.run()
        animal.sleep()

    常用的内置函数

    __del__
    当对象被删除前会自动调用 该方法
    声明时候会删除对象?
    1.程序运行结束 解释器退出 将自动删除所有数据
    2.手动调用del 时也会删除对象

    注意:该函数不是用来删除对象的

    使用场景
    当你的对象在创建时,开启了不属于解释器的资源 例如打开了一个文件
    必须保证当对象被删除时 同时关闭额外的资源 如文件


    也称之为析构函数 构造 的反义词
    构造 指的是从无到有
    析构 值从有到无
    简单的说就对象所有数据全部删除


    总结:__del__该函数 用于 在对象删除前做一些清理操作

    # 假设要求每一个person对象都要绑定一个文件
    class Person:
        def __init__(self,name,path,mode="rt",encoding="utf-8"):
            self.name = name
            self.file = open(path,mode,encoding=encoding)
    
    
    
        # 读取数据的方法
        def read_data(self):
            return self.file.read()
    
    
        def __del__(self):
            print("del run!")
            self.file.close()

    反射

    英文中叫反省 (自省)

    面向对象中的反省 指的是,一个对象必须具备,发现自身属性,以及修改自身属性的能力;

    一个对象在设计初期,可能考虑不够周全后期需要删除或修改已经存在的属性, 和增加属性

    反射就是通过字符串来操作对象属性

    涉及到的方法:

    hasattr 判断是否存在某个属性

    getattr 获取某个属性的值

    setattr 新增或修改某个属性

    delattr 删除某个属性

    案例:

    ```python
    class MY_CMD:
    
        def dir(self):
            os.system("dir")
    
        def ipconfig(self):
            os.system("ipconfig")
    
    cmd = MY_CMD()
    
    while True:
        name = input("请输入要执行的功能:")
        if hasattr(cmd,name):        #首先判断判断属性是否存在 
            method = getattr(cmd,name)  #存在则通过getter来获取该属性
            print(method)
            method()
        else:
            print("sorry this method is not exists....!")
    ```

    动态导入模块

    直接写import 的模块是基于已经知道有哪些需要使用到的模块 称为静态导入,

    动态导入是 在任何需要的 时候通过指定字符串类型的包名称来导入需要的模块

    import importlib
    mk = importlib.import_module(m_name)
    mk 即导入成功的模块
    """
    该方式常用在框架中 因为框架设计者不可能提前预知后续需要的模块和类

  • 相关阅读:
    char*”类型的值不能用于初始化“LPTSTR , Const char*”类型的值不能用于初始化“LPCTSTR
    LPCTSTR和LPTSTR和char *
    C++ char*,const char*,string的相互转换(转)
    vs2017 开发 C++ 操作mysql的动态库
    VS2017 创建C++Dll动态库(二)
    VS2017中托管C++程序调用托管C++生成的动态库,程序无法调试的问题(转)
    win10 MySQLroot 远程连接
    c++中c_str()的用法详解(转)
    【605】Python的开发环境相关 (不同版本python、pip)
    【604】Python class __dict__.update的使用
  • 原文地址:https://www.cnblogs.com/1624413646hxy/p/10896303.html
Copyright © 2020-2023  润新知