zoukankan      html  css  js  c++  java
  • 26 封装 反射 常用内置函数

    封装

    什么是封装 what

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

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

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

    python中属性的权限分为两种

    1.公开的

    没有任何限制 谁都能访问

    2.私有的

    只有当前类本身能够访问

    默认为公共的

    how

    在python中用双下划线开头的方式将属性隐藏起来(设置成私有的)

     

    类中所有双下划线开头的名称如__x都会在类定义时自动变形成:_类名__x的形式:
    lass A:
        __N=0 #类的数据属性就应该是共享的,但是语法上是可以把类的数据属性设置成私有的如__N,会变形为_A__N
        def __init__(self):
            self.__X=10 #变形为self._A__X
        def __foo(self): #变形为_A__foo
            print('from A')
        def bar(self):
            self.__foo() #只有在类内部才可以通过__foo的形式访问到.
    
    #A._A__N是可以访问到的,
    #这种,在外部是无法通过__x这个名字访问到。

     

    为什么要封装 why

    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 show_id_card(self):
           # 可以在这里添加额外的任何逻辑代码 来限制外部的访问
           
           #在类的内部 可以访问
           print(self.__id_card)

    对私有属性的访问以及修改

    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!")

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

    一个为内部提供支持的方法,不应该让外界直接访问,那就封装起来 ,如下例中的 user_auth等...

    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("记录流水....")

    封装的原理:

    python是通过 变形的方式来实现封装:
    在名称带有双下划线开头的变量名字前添加_类名 如_Person__id_card
    当然通过变形后的名字可以直接访问被隐藏的属性 但通过不应该这么做
    1.这种机制也并没有真正意义上限制我们从外部直接访问属性,知道了类名和属性名就可以拼出名字:_类名__属性,
    然后就可以访问了,如a._A__N,
    即这种操作并不是严格意义上的限制外部访问,仅仅只是一种语法意义上的变形,主要用来限制外部的直接访问。
    2.变形仅在类的定义阶段发生一次 后续再添加的带有双下划线的任何属性都不会变形 就是普通属性

     

    什么时候用 where

    封装属性

    当这个对象存在一个机密性的属性 例如 人的身份证 银行卡密码等等,这样属性不应该被外界直接 访问当 ,那就封装起来

    Person 密码 Teacher 工资

    封装方法

    一个为内部提供支持的方法,不应该让外界直接访问,那就封装起来 ,如下例中的 user_auth等..

     

    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"]

     

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

    property是一种特殊的属性,访问它时会执行一段功能(函数)然后返回值

    将一个类的函数定义成特性以后,对象再去使用的时候obj.name,根本无法察觉自己的name是执行了一个函数然后计算出来的,这种特性的使用方式遵循了统一访问的原则

    什么是计算属性 一个属性 它的值不是固定的 而是通过计算动态产生的 BMI

    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

    多态 :

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

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

    多态
    某种事物具备多个不同形态
    例如 水:   气态 固态 液态
        动物: 人 猫 猪
        汽车人: 汽车 飞机 人型

    OOP中 标准解释: 多个不同类型对象 可以响应同一个方法 并且产生不同结果

    多态的带来的好处:
      只需要学习基类中的使用方法即可, 不需要关心具体的哪一个类 以及实现的   以不变应万变   提高了灵活性
      提高扩展性
       
      如果没有多态 需要分别学习 person cat pig 的不同使用方法 这对于使用者而言太麻烦了

    如何实现多态:
    鸭子类型 就是典型的多态 多种不同类型 使用方法一样

    案例:

    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()

     

    反射

    英文中叫反省 (自省)

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

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

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

     

     

    涉及到的方法:

    hasattr 判断是否存在某个属性

    getattr 获取某个属性的值

    setattr 新增或修改某个属性

    delattr 删除某个属性


    好处
    1.实现可插拔机制

    可以事先定义好接口,接口只有在被完成后才会真正执行,这实现了即插即用
    class CMD:
    def dir(self):
    os.system('dir')

    def ip(self):
    os.system('ip')

    cmd=CMD

    while True:
    name=input('输入执行功能')
    if hasattr(cmd,name):
    method=getattr(cmd,name)
    print(method)
    method()

    else:
    print('无')


    2.动态导入模块(基于反射当前模块成员)
    """
    直接写import 称之为静态导入 建立在一个基础上:提前已经知道有这个模块
    动态导入 指的是 在需要的任何时候 通过指定字符串类型的包名称来导入需要的模块
    import importlib
    mk = importlib.import_module(m_name)
    mk 即导入成功的模块
    """
    该方式常用在框架中 因为框架设计者不可能提前预知后续需要的模块和类
     

    案例:

    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....!")

     

     

    常用的内置函数

     

    __str__

    改变对象的字符串显示__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__())

     

    __del__

    """
    __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()

     

    
    

     

     

     

  • 相关阅读:
    Ubuntu 14.04 apt-get update失效解决(转)
    linux内核动态调试技术
    Ubuntu18.04开机挂载硬盘
    valgrind memcheck使用方法及效果(转)
    网络测试工具netperf(转)
    开发pc端项目可支持多个窗口登陆
    sql常用语句
    包装类和基础类的区别
    @param
    前台后台的顺序
  • 原文地址:https://www.cnblogs.com/komorebi/p/10897397.html
Copyright © 2011-2022 走看看