zoukankan      html  css  js  c++  java
  • Python Day 26 封装、property装饰器、多态、__str__内置函数、__del__内置函数、反射、动态导入模块

      阅读目录

       

    1、封装
    2、封装属性
    3、封装方法
    4、封装原理
    5、property装饰器
    6、多态
    7、__str__内置函数
    8、__del__内置函数
    9、反射
    10、动态导入模块
    11、反射在框架中的应用

      ##封装

    #什么是封装?
    对外部隐藏内部的属性,以及实现细节  , 给外部提供使用的接口 
    
    注意:封装有隐藏的意思,但不是单纯的隐藏 
    
    学习封装的目的.就是为了能够限制外界对内部数据的访问 
    
    python中属性的权限分为两种
    
    1.公开的
    
    ​    没有任何限制 谁都能访问 
    
    2.私有的 
    
    ​    只有当前类本身能够访问 
    默认为公共的
     
    #为什么需要封装
    1.提高安全性  
    
    ​    封装属性    
    
    2.隔离复杂度     
    
    ​    封装方法

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

    #如何封装
    在属性名或者方法名前添加两个下划线__,将其设置为私有的

    #思考:封装可以明确地区分内外,封装的属性可以直接在内部使用,而不能被外部直接使用,然而定义属性的目的终归是要用,外部要想用类隐藏的属性,需要为其提供接口,
    让外部能够间接地使用到隐藏起来的属性,那这么做的意义何在?
       答:可以在接口附加上对该数据操作的限制,以此完成对数据属性操作的严格控制。


      ##封装属性

    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!")
    
    # stu1 = Student("rose",20,"man","111111111111111111")
    #
    # print(stu1.name)
    # print(stu1.id_card)
    # stu1.id_card = "123"
    # print(stu1.id_card)
    
    stu1 = Student("rose",20,"man","111111111111111111")
    # print(stu1.id_card)
    # print(stu1.__id_card)
    # stu1.show_id_card()
    # stu1.set_id_crad("222222222222222222")
    
    # stu1.show_id_card()
    
    # id = stu1.get_id_card()
    # print(id)
    
    # stu1.set_id_crad(123)
    stu1.set_id_crad("555555555555555555")
    # print(stu1.get_id_card())
    
    print(stu1.get_id_card("1232"))

      ##封装方法

    什么样的方法应该被封装起来 ?
    
    ​    答:一个为内部提供支持的方法,不应该让外界直接访问,那就封装起来 ,如下例中的 user_auth等...
    
    #示例1
    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("记录流水....")
    atm = ATM()
    # atm.user_auth()
    # atm.input_money()
    # atm.save_record()
    
    # atm.withdraw()
    
    # atm.save_record()

      ##封装原理

    python是通过 变形的方式来实现的封装
    如何变形 在名称带有双下划线开头的变量名字前添加_类名  如_Person__id_card
    当然通过变形后的名字可以直接访问被隐藏的属性  但通过不应该这么做
    变形仅在类的定义阶段发生一次 后续再添加的带有双下划线的任何属性都不会变形  就是普通属性 
    
    #示例1
    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__)
    
    # print(p._Person__id_card)
    p.__gender = "man"
    
    print(p.__dict__)

      ##property装饰器

    作用: 将一个方法伪装成普通属性 
    
    为什么用 property    希望将访问私有属性和普通属性的方式变得一致
    
    与property相关的 两个装饰器 
    
    setter 
    
    ​    用点语法 给属性赋值时触发   
    
    deleter 
    
    ​    用点语法删除属性时触发 
    
    #示例
    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"]
            # del self.__salary
    
        #通常property 用于操作私有的属性
    t = Teacher("egon",38,100000)
    #
    # print(t.get_salary())
    #
    # t.set_salary(5000)
    #
    # print(t.get_salary())
    # print(t.name)
    
    # 被封装的属性在访问时  需要调用方法  而普通属性直接点就ok 这样一来对于对象的使用者而言
    # 必须知道要访问的属性 是私有的还是公开 然后调用对于的方法    用起来麻烦
    # 此时  我们的目标是 让访问私有属性 和访问普通属性的方式一直
    # property 装饰器  就是用来将一个方法伪装成属性
    
    
    # print(t.salary)
    # t.salary = 500
    # print(t.salary)
    
    # 删除对象属性
    # del t.name
    #
    # print(t.name)
    
    
    # del t.salary
    
    
    # a = {"name":123}
    # # a.pop("name")
    #
    # del a["name"]
    #
    # print(a)
    
    del t.salary
    #
    # t.del_salary()
    
    
    # t.salary = 1
    #
    #
    # # print(t.salary)
    #
    # del t.salary
    
    
    # t.get_salary()
    # t.set_salary(800)
    # t.delete_salary()
    
    # t.salary
    # t.salary = 800
    # del t.salary

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

    什么是计算属性   一个属性 它的值不是固定死的 而是通过计算动态产生的。
    例如:BMI指数
    
    #示例1
    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.weight = 60
    # print(p.BMI)
    
    
    # print(p.get_BMI())
    # p.weight = 60
    #
    # print(p.get_BMI())
    #
    # print(p.name)
    # print(p.get_BMI())
    
    #
    # print(p.BMI)
    # p.weight = 60
    # print(p.BMI)
    # p.BMI = 10

      ##封装能不能被继承问题

    # 被封装的内容(私有的)  不可以被继承
    # class A:
    #     __name =  "rose"  # _A__name
    #
    #     def __say_hi(self):
    #         print("A say: hi")
    # class B(A):
    #     def test(self):
    #         # print(super().__name)  #_B__name
    #         print(A._A__name)
    #     # pass
    # b = B()
    # b.test()

      ##多态

    多态不是一个具体的技术  或代码
    
    指的是 多个不同类型对象 可以响应同一个方法 ,产生不同结果
    
    例如 水:   气态  固态  液态
         动物: 人  猫  猪
         汽车人:  汽车 飞机  人型
    
    OOP中 标准解释: 多个不同类型对象 可以响应同一个方法  并且产生不同结果
    
    多态的带来的好处:
        只需要学习基类中的使用方法即可, 不需要关心具体的哪一个类 以及实现的   以不变应万变   提高了灵活性
        提高扩展性 
        
        如果没有多态  需要分别学习 person  cat pig 的不同使用方法 这对于使用者而言太麻烦了
    
    如何实现多态:
        鸭子类型 就是典型的多态 多种不同类型 使用方法一样 
    
    #示例1
    class Person():
    
        def bark(self):
            print("Hello!")
    
        def run(self):
            print("两条腿跑!")
    
        def sleep(self):
            print("躺着睡!")
    
    
    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("侧躺着睡!")
    
    
    # person1 = Person()
    # cat1 = Cat()
    # pig1 = Pig()
    
    # person1.sleep()
    # cat1.sleep()
    # pig1.sleep()
    # 如果没有多态  需要分别学习 person  cat pig 的不同使用方法 这对于使用者而言太麻烦了
    #

    # 一个用来管理动物的方法   只要你传入是一个动物 我就按照动物的标准来使用 完全不用考虑你具体是什么类型

    class Dog:
    def bark(self):
    print('汪汪汪')
    def run(self):
    print('四条腿在跑')
    def sleep(self):
    print('躺着睡')
    class Cat:
    def bark(self):
    print('喵喵喵')
    def run(self):
    print('四条腿在跑')
    def sleep(self):
    print('趴着睡')
    def manage_animal(animal):
    print('========%s====='%animal.__class__.__name__)
    animal.bark()
    animal.run()
    animal.sleep()
    dog = Dog()
    manage_animal(dog)

    cat = Cat()
    manage_animal(cat)
     
     
    #  无处不在的多态
     
    # def MY_LEN(obj):
    #     return obj.__len__()
    #
    # print(MY_LEN("abcdefg"))
    # print(MY_LEN([1,2,3,4]))
    # print(MY_LEN({"name":123}))

    print(len("1231212121"))
     
    #总结

    继承:是类与类之间的关系,什么是什么的关系,好处是通过继承可以使用父类中的属性和方法

    封装:对外部隐藏属性和实现细节,同时提供调用的接口,目的提高数据的安全度 和隔离复杂度

    多态:不同类型的对象使用同一方法产生不同的结果,好处是学习统一标准,提高灵活性和拓展性

      ##常用的内置函数

    #__str__
    类中的__str__
        该方法在object中有定义 默认行为 返回对象类型以及地址  <__main__.Person object at 0x0000016F450C7390>
        在将对象转为字符串时执行
        注意:返回值必须为字符串类型
        子类可以覆盖该方法来完成 对打印内容的自定义
    
    #示例1
    class Person:
        def __init__(self,name,age):
            self.name = name
            self.age = age
        # 将对象转换为字符串时执行
        def __str__(self):
            print("str run")
            return "my name is %s , age is %s" % (self.name,self.age)
    
    
    p = Person("rose",20)
    # print(p) #在打印前都会现将要打印的内容转为字符串  通过调用__str__函数
    
    str(p)
    
    #__del__
    """
    __del__
    当对象被删除前会自动调用 该方法
    声明时候会删除对象?
        1.程序运行结束 解释器退出 将自动删除所有数据
        2.手动调用del 时也会删除对象
    
    注意:该函数不是用来删除对象的
    
    使用场景
    当你的对象在创建时,开启了不属于解释器的资源 例如打开了一个文件
    必须保证当对象被删除时 同时关闭额外的资源  如文件
    
    
    也称之为析构函数  构造 的反义词
        构造 指的是从无到有
        析构 值从有到无
        简单的说就对象所有数据全部删除
    
    
    总结:__del__该函数 用于 在对象删除前做一些清理操作
    """
    
    #示例1
    # 假设要求每一个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()
    
    
    # p = Person("jack")
    
    # a = 10
    
    # f = open("test.txt")
    # print(f.read())
    # f.close()
    
    p2 = Person("rose","本周内容")
    print(p2.read_data())

      ##反射

    #英文中叫反省 (自省)   
    
    面向对象中的反省 指的是,一个对象必须具备,发现自身属性,以及修改自身属性的能力;   
    
    一个对象在设计初期,可能考虑不够周全后期需要删除或修改已经存在的属性, 和增加属性 
    
    反射就是通过字符串来操作对象属性
    
    涉及到的方法:
    1、hasattr 判断是否存在某个属性
    
    2、getattr    获取某个属性的值
    
    3、setattr    新增或修改某个属性 
    
    4、delattr 删除某个属性 
    
    #示例1
    import os
    class  Student:
    
        def __init__(self,name):
            self.name = name
    
    
    stu = Student("rose")
    # stu.age = 18
    #
    # print(stu.name)
    # print(hasattr(stu,"name"))
    print(getattr(stu,"name"))
    #
    # setattr(stu,"name","jack")
    # print(getattr(stu,"name"))
    #
    # delattr(stu,"name")
    # print(stu.name)
    
    
    #示例2
    
    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)
            print(method)
            method()
        else:
            print("sorry this method is not exists....!")

      ##动态导入模块

    直接写import 称之为静态导入  建立在一个基础时 提前已经知道有这个模块
    
    动态导入  指的是  在需要的任何时候 通过指定字符串类型包名称来导入需要的模块
    import importlib
    mk = importlib.import_module(m_name)
    mk 即导入成功的模块
    
    该方式常用在框架中 因为框架设计者不可能提前预知后续需要的模块和类
    动态引入引入一个模块,name可以是相对路径和绝对路径,如果是相对路径的话,这package就是相应的包名

    #示例 import importlib m_name = input("请输入要导入的模块名称:") #执行要输入模块名称:build_house.core mk = importlib.import_module(m_name) print(mk) from build_house import conf print(conf) 注解:print(mk) 和print(conf) 结果一样的

      ##反射在框架中的应用

    #core.py文件
    import importlib
    from 代码.build_house import conf
    def building():
        print("毛坯房建造完成.......")
        # 读取用户提供配置信息 来加载用户所需要的一系列装饰品
        for cls_info in conf.decorations:
            # print(cls_info)
            # 切割类名和模块路径
            m_name,cls_name = cls_info.rsplit(".",1)
            # print(m_name,cls_name)
            # 导入模块
            mk = importlib.import_module(m_name)
            # print(mk)
            # 从模块中获取类
            if not hasattr(mk,cls_name):
                continue
            cls = getattr(mk,cls_name)
            obj = cls()
            print(obj)
    
    building()
    
    #conf.py文件
    decorations = ["build_house.my_decoration.Table",
                   "build_house.my_decoration.Bed",
                   "build_house.my_decoration.Light",
                   "other_decoration.Sofa"]
    
    #my_decoration.py文件
    class Table:
        pass
    
    class Light:
        pass
    
    class Bed:
        pass
  • 相关阅读:
    SHELL
    Docker
    RHCE内容记要
    mysql基本知识的总结
    Linux启动提示Kernel panic
    配置tomcat、nginx实现反向代理(需操作)
    linux下nginx的安装和配置
    linux下安装mysql5.7(centos6.0)
    linux打包解压包(.tar .gz .tar.gz .zip)
    多重继承下的类型转换
  • 原文地址:https://www.cnblogs.com/liangzhenghong/p/10895381.html
Copyright © 2011-2022 走看看