• day26 封装、多态、常用内置函数【__del__、__str__、__setattr__、__getattr__】、反射【hasattr、getattr、setattr、delattr】、动态导入模块


    今日内容

    一、封装
    什么是封装
    对外不对内,不让类外部直接使用
    对外部隐藏内部的属性以及实现的细节,隐藏并不是完全不给外部使用,给外部提供使用的接口


    python中属性权限分两种:公开的【没有任何限制,外界可以操作数据】-- 默认
    私有的【只有当前类本身能够访问】
    为什么要学习封装
    1.提高安全性【属性】,什么样的属性需要封装?
    当这个对象存在一个机密必的属性,例如人的身份证、银行卡密码等

    2.隔离复杂度【方法】,什么样的方法需要封装?
    一个为内部提供支持的方法,不应该让外界直接访问的,如:在ATM项目中取款,只提供给外界一个入口,
    类内部自调登入功能,成功后自调显示余额、输入取款金额、保存记录等。
    还有如电脑开机键,就做了一系列的封装


    如何封装
    通过在类定义阶段对需要封装的属性/方法变形:__开头的属性/方法名会在类定义阶段变形添加_类名 如:_person__id_card
    变形后实在要访问,可以用字典的方式访问:obj.__dic__['_person__id_card']
    封装后还是可以给外界使用的

    属性封装 --
    1)类内定义一个接口函数,再把结果return回给外界调用者,这样return前可以添加一些条件限制,
    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_card(self, new_id):
    if isinstance(new_id, str) and len(new_id) == 18:
    self.__id_card = new_id
    else:
    raise Exception('身份证号码,必须是之符串,且长度必须为18!')

    stu = Student('fanny', 18, 'female', 123456)
    print(stu.get_id_card('123'))

    stu.set_id_card('012345678945632101')
    print(stu.get_id_card('123'))

    解决方法: 用@property将一个方法伪装成一个属性,
    用@id_card【名字等于@property下函数名】.setter来修改属性
    用@

    class Student:
    def __init__(self, name, age, gender, id_card):
    self.name = name
    self.age = age
    self.gender = gender
    self.__id_card = id_card


    @property #getter 用于访问私有属性的值,也可以设置普通属性【初始化不能定义,如BMI计算】
    def id_card(self):
    pwd =input('pwd:').strip()
    if pwd == '123':
    return self.__id_card
    print('密码错误,不能访问')

    @id_card.setter #用来设置私有属性的值,也可以设置普通属性
    def id_card(self, new_id):
    if isinstance(new_id, str) and len(new_id) == 18:
    self.__id_card = new_id
    else:
    print('身份证号码,必须是之符串,且长度必须为18!')

    @id_card.deleter #用来删除私有属性的值,也可以删除普通属性
    def id_card(self):
    print('can not delete salray!')
    del self.__dict__['_Student__id_card']



    stu = Student('fanny', 18, 'female', 123456)
    # stu.id_card

    stu.id_card = '123569874123654780'
    # print(stu.id_card)

    # print(stu.__dict__) #{'name': 'fanny', 'age': 18, 'gender': 'female', '_Student__id_card': '123569874123654780'}

    del stu.id_card

    stu.id_card # 'Student' object has no attribute '_Student__id_card'

    Property的另一种使用场景【设置普通属性】:计算属性BMI

    class Persoon:
    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, nwe_BMI):
    print('BMI 不支持自定义...')

    p1 = Persoon('egon', 1.7, 80)
    print(p1.BMI)
    p1.BMI =10

    二、多态:
    多太指的是同一种事物的多种形态
    多个不同类型对象,可以响应同一方法,并且产生不同结果, 【统一】以不变应万变,提高了灵活性、扩展性

    多态的好处: 可以在不用考虑对象具体类型前提下而直接使用对象,不需要关心各个类型对象的具体实现细节

    在多态背景下,父类不是让子类继续它的功能,而是建立了一种规范

    python 崇尚鸭子类型 指的是子类并不需要从属于哪个类,只要多个类之间约定好都定义同名的函数
    统一后就用一个接口中,使用方便

    例:一个用来管理动物的方法,只要你传入是一个有同名方法的对象,就可以使用
    class Cat:
    def dark(self):
    print('喵喵')

    def run(self):
    print('轻轻地跑')

    def sleep(self):
    print('趴着跑')

    class Pig:
    def dark(self):
    print('哼哼')

    def run(self):
    print('四条腿跑')

    def sleep(self):
    print('侧躺着睡')

    class Manger_anmal:
    def dark(self, obj):
    obj.dark()

    def run(self, obj):
    obj.run()

    def sleep(self, obj):
    obj.sleep()

    cat = Cat()
    pig1 = Pig()

    obj = Manger_anmal()
    obj.dark(cat)
    obj.dark(pig1)

    三、常用的内置函数: __str__ __del__ __setattr__ __getattr__

    3.1 __str__ # 在对象被打印时自动触发,可以用来定义对象被打印时的输出信息
       # 注意:必须返回一个字符串类型的值

    class People:
    def __init__(self, name, age ):
    self.name = name
    self.age = age

    def __str__(self):
    print('run....')
    return '<name: %s age:%s>' %(self.name, self.age )

    obj1 = People('egon', 18)
    print(obj1) #print(obj1.__str__())

    3.2 __del__ : # 该函数不是用来删除对象的,【在对象删除前做一些清理操作】是用来关闭清理回收对象以外其他相关资源,比如打开文件后,通知操作系统关闭文件爱你
    触发时机:
    1.程序运行结束 解释器退出时,自动删除所有数据 【例1】
    2.在对象被删除时【del obj】触发该方法,【例2】
    -----------------------------------
    例1:
    class Foo:
    def __del__(self):
    print('run ...')

    obj = Foo()
    print('===========')

    输出:
    ===========
    run ...

    --------------------------------------------
    例2:
    class Foo:
    def __del__(self):
    print('run ...')

    obj = Foo()
    del obj
    print('===========')

    输出:
    run ...
    ===========

    3.3 __setattr__
    添加/修改属性会触发它的执行

    3.4 __getattr__    只有在使用点调用属性且属性不存在的时候才会触发
    
    
    class Myclass:
    name='egon'

    def __getattr__(self, item):
    print('这是__getattr__')

    def __setattr__(self, key, value):
    print('这是__setattr__')

    s1= Myclass()
    print(s1.name)
    # print(s1.age)
    # s1.name='fanny
    四、反射  通过字符串来操作属性

    hasatter(obj,'dir') 判断obj是否有某个属性 返回一个bool值 【obj是任何对象】
    #print('dir' in MY_CMD.__dict__)


    getattr(cmd, 'dir',None) 返回一个属性,可能是数据属性【变量名】,也可能是一个方法属性【函数对象】
    返回一个dir绑定方法,加()可运行 #<bound method MY_CMD.dir of <__main__.MY_CMD object at 0x000001B73AAE9470>>

    setattr(cmd, 'x', 222 ) 新增或修改某个属性,有'x'就修改该属性的值,没有就新增一个属性及值
    print(cmd.x)

    setattr(cmd, 'y', 666 )
    print(cmd.y)


    delattr(cmd, 'name') 删除某个属性,只能删除该对象自己私有的属性,如果该属性是类的,就不能删,可以将cmd变成
    delattr(cmd, 'x') #AttributeError: x
    delattr(MY_CMD, 'x')

    import os
    class MY_CMD:
    x = 111
    def __init__(self, name):
    self.name = name


    def dir(self):
    os.system("dir")

    def ipconfig(self):
    os.system("ipconfig")

    cmd = MY_CMD('fanny')

    print(hasattr(MY_CMD, 'dir')) #print('dir' in MY_CMD.__dict__)
    print('dir' in MY_CMD.__dict__)

    print(hasattr(cmd, 'name'))
    print('name' in cmd.__dict__)
    print('name' in MY_CMD.__dict__) #$False


    getattr(cmd, 'dir',None)()
    print(getattr(cmd, 'name', None))
    setattr(cmd, 'x', 222 )
    print(cmd.x)

    setattr(cmd, 'y', 666 )
    print(cmd.y)

    delattr(cmd, 'name')
    delattr(cmd, 'x') #AttributeError: x
    delattr(MY_CMD, 'x')


    五、动态导入模块
    直接写import为静态导入,建立在提前已经知道有这个模块
    动态导入 指的是 在需要的任何时候,通过指定字符串类型的包名称来导入需要的模块
    该方式常用在框架中,因为框架设计者不可能提前预知后续需要的模块和类

    import importlib
    mk = importlib.import_module(m_name)
  • 相关阅读:
    set集合操作
    python中字符串操作
    字典----增删改查遍历
    C#反射回顾笔记
    消息队列之ActiveMQ学习笔记(二、C#实例实现)
    消息队列之ActiveMQ学习笔记(一、下载及安装)
    依赖注入之AutoFac
    layer弹框层学习笔记
    VS自定义代码块Code Snippet
    博客园添加链接
  • 原文地址:https://www.cnblogs.com/qingqinxu/p/10889764.html
Copyright © 2020-2023  润新知