zoukankan      html  css  js  c++  java
  • day26 封装、多态、内置函数、反射、动态导入

    今日内容

    1、封装

    什么是封装?

    封装从字面意思上看就只将某种东西封起来装好,当我们代码中的某些方法与属性不想让外界进行访问时,就对这些属性进行特殊的处理,使这种属性或者方法不能被外界直接进行访问或者修改,这种方法就称之为封装

    但是,在python中没有完全意义的封装,封装只是在内部进行了变形,使其使用原变量名不能进行访问

    同时,有些父类的方法,如果不想让子类进行覆盖就将父类的方法设置为私有属性

    封装的方法:

    在python中如果需要对某个属性或方法进行封装是只需要在变量名前设置为__开头的即可,此时在在外界进行访问时就不能访问这个属性或方法

    封装的原理:

    我们在进行封装时,实际上是对封装的属性或方法进行了变形,当类进行定义时,如果属性或者方法是以__开头的就会对这个属性进行变形,变形方式为:

    __前面加上_类名变为_类名__属性名或方法名

    注意:变形的操作只在定义类时执行一次

    在python中,并不会限制用户访问私有属性及方法,私有的属性及方法还是可以被外界访问的,只要自己将方法前面添加_类名就可以访问私有的属性及方法

    其实很多时候你去调用一个模块的功能时会遇到单下划线开头的(socket.socket,sys.home,sys._clear_type_cache),这些都是私有的,原则上是供内部调用的

    class Person:
        def __init__(self,name,age):
            self.name = name
            self.__age = age
    
    p = Person("lee",20)
    print(p.name)
    # print(p.__age)  # AttributeError: 'Person' object has no attribute '__age'
    p.__age = 18
    print(p.__age)  # 18
    print(p.__dict__)  # {'name': 'lee', '_Person__age': 20, '__age': 18}

    从上例中可以看出:当把属性设置为__开头时就不能在外界直接访问及修改了,如果直接使用 对象.__方法名进行设置,不是对原来的方法进行设置,而是在名称空间直接设置了一个新的变量名

    封装的目的

    封装不是单纯意义的隐藏,封装会明确的区分内外,在类的内部可以直接使用但是在外部就不可以直接使用

    封装的目的:

    1、提高安全性:提高安全性主要是针对属性而言的,封装后属性的值不能直接被外界访问及修改,可以保证数据的安全性

    2、隔离复杂度:隔离复杂度是针对于方法而言的,我们将类中具体的逻辑私有化,再将其封装到一个方法中供外界访问,这样用户只需要进行一次调用就可以直接访问,对用户而言降低了复杂度

    class ATM:
        def __card(self):
            print('插卡')
            
        def __auth(self):
            print('用户认证')
            
        def __input(self):
            print('输入取款金额')
            
        def __print_bill(self):
            print('打印账单')
            
        def __take_money(self):
            print('取款')
            
        def withdraw(self):
            self.__card()
            self.__auth()
            self.__input()
            self.__take_money()
            self.__print_bill()
        
    atm = ATM()
    atm.withdraw()
    # 插卡
    # 用户认证
    # 输入取款金额
    # 取款
    # 打印账单

    上述方法对于用户而言只是进行了取款操作,但是在类的内部通过私有方法已经进行了一系列操作

     

    property装饰器

    property是一个属性装饰器,可以将方法伪装成属性

    实际上,property是一个类,在使用是就是调用这个类产生一个实例化对象,这个对象经常使用的方法有三种:`

    getter setter deleter`

    其中:

    getter在调用property时就会自动调用

    setter在设置方法时调用

    deleter在删除方法时调用

    property使用场景一:供私有属性使用
    class Person:
        def __init__(self,name,age):
            self.name = name
            self.__age = age
            
        def get_age(self):
            print(self.__age)
            
        def set_age(self,new_age):
            self.__age = new_age
    p =Person("lee",18)
    p.name
    p.get_age()

    通过上例中的方法可以进行私有属性的访问及修改,但是这样我们在访问name属性时可以使用 对象.name进行访问,但是访问age属性是就需要使用 对象.get_age() 来进行访问,同样都是属性但是访问方法却不相同,为了使用户对属性的访问方式相同,此时就需要使用 propety 装饰器

    class Person:
        def __init__(self, name, age):
            self.name = name
            self.__age = age
    
        @property
        def age(self):
            return (self.__age)
    
        @age.setter
        def age(self, new_age):
            self.__age = new_age
    
        @age.deleter
        def age(self):
            del self.__dict__["_Person__age"]
    
    
    p = Person("lee", 18)
    print(p.name)
    print(p.age)
    p.age = 20
    del p.age
    print(p.age) # 会报错

    property使用场景二:计算属性

    在初始化函数中,有时并不是所有的属性都是可以直接就能得出的,有时需要进行计算,但是如果在初始化函数中进行计算,那么在这个量只能在创建对象时初始化一次,不能进行修改,但是,如果将这个属性设置为方法,就可以进行重复的变化,但是这个值归根结底就是个属性,在访问时想以属性的方式进行访问,此时就需要使用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)
    # p.weight = 60
    # print(p.BMI)

    2、多态

    什么是多态?

    多态就是一种事物的多种形态

    oop中多态就是不同类型的对象可以响应同一种方法,得到不同的响应结果

    # 定义一个动物的类
    class Animal:
        def bark(self):
            pass
    
        def sleep(self):
            pass
    
        def run(self):
            pass
    
        
    # 定义一个猫类
    class Cat(Animal):
        def bark(self):
            print("喵喵喵")
    
        def sleep(self):
            print("躺着睡")
    
        def run(self):
            print("四条腿跑")
    
    # 定义一个人类
    class Person(Animal):
        def bark(self):
            print("hi")
    
        def run(self):
            print("四条腿跑")
    
        def sleep(self):
            print("躺着睡")
    
            
    # 定义一个狗类
    class Dog(Animal):
        def bark(self):
            print("汪汪汪")
    
        def sleep(self):
            print("侧躺着睡")
    
        def run(self):
            print('四条腿跑')
    
    # 定义一个管理员类用来管理动物
    class ManagementAnimal:
        def Manage(self,animal):
            animal.bark()
            animal.sleep()
            animal.run()
    
     
    dog = Dog()
    p = Person()
    cat = Cat()
    
    m = ManagementAnimal()
    m.Manage(p)
    m.Manage(dog)
    m.Manage(cat)

    在上例中:

    动物类、狗类、猫类、人类等产生的不同对象可以同时调用barksleeprun等方法,但是这些方法的执行结果是不相同的,这种就称之为多态

    从上述例子可以看出多态的优点:

    1、可以是对象的调用更加的灵活,不论对象如何改变,调用对象方法的方式是相同的

    2、可以提高程序的扩展性,在创建一个新的动物类是不需要更改Manager的代码就能进行使用

     

    在python中如果想要强制性的规定动物类必须具有这些个属性,可以导入abc模块

    import abc
    
    class Animal(metaclass=abc.ABCmeta)
        @abc.abstractmethod
        def bark(self):
            pass
        
        def sleep(self):
            pass
    class Cat(Animal):
        def sleep(self):
            print("正在叫!")
    
    cat = Cat()

    如果调用了abc模块,那么子类继承后在进行实例化时,如果不将类中含有abstractmethod的方法全部重新定义,就会报错,其中没有abstractmethod的方法不受限制

     

    虽然在Python中可以使用abc模块进行限制,但是python编程更多的是建议,而不是约束

    所以python中更多的是建议用户使用鸭子类型

     

    3、内置函数

    __str__

    _str_是系统内置的函数,当我们需要对类转化成字符串时就会执行

    类中的__str__
    该方法在object中有定义 默认行为 返回对象类型以及地址 <__main__.Person object at 0x0000016F450C7390>
    在将对象转为字符串时执行
    注意:返回值必须为字符串类型
    子类可以覆盖该方法来完成 对打印内容的自定义

    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__该函数 用于 在对象删除前做一些清理操作

    # 假设要求每一个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())

    4、反射

    英文中叫反省 (自省)

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

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

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

    涉及到的方法:
    hasattr 判断是否存在某个属性
    getattr    获取某个属性的值
    setattr    新增或修改某个属性 
    delattr 删除某个属性 
    
    案例:
    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....!")

    5、动态导入模块

    直接写import 称之为静态导入 建立在一个基础上:提前已经知道有这个模块

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

    import importlib mk = importlib.import_module(m_name) mk 即导入成功的模块

    该方式常用在框架中 因为框架设计者不可能提前预知后续需要的模块和类

     

  • 相关阅读:
    poj 3255
    (DP) bzoj 2091
    (最短路) bzoj 2118
    (点双联通分量) poj 2942
    (树直径) bzoj 1509
    (离线处理+BFS) poi Tales of seafaring
    (并查集+DFS) poi guilds
    (记忆话搜索)POI Fibonacci Representation
    (DP) POI Bytecomputer
    (DP) bzoj 1296
  • 原文地址:https://www.cnblogs.com/lice-blog/p/10897039.html
Copyright © 2011-2022 走看看