• day 26 对象的封装 抽象和接口


    一、上节回顾:

    复习:

    面向对象的三大特性:  继承  多态  封装

    (1)继承:

        #单继承:最常用的

      #多继承:钻石继承问题提现差别:经典类(深度优先)和新式类(广度优先),mro

           #新式类:super

      #父类子类调用方法的先后顺序

        #只要子类有就用子类的,子类没有就找父类

        #子类父类都想用,就先找子类,在子类中调用父类( super().hahaha() )

      #在多继承中,super不只是寻找当前的父类,而是依据mro顺序,

      #从A节点出发,依据广度优先排序查找下一类

    、 #派生:子类中可能有,派生属性和派生方法

       #多态和鸭子类型

    class Teacher:
        pass
    class School:
        pass
    class Professor(Teacher,School):
        pass
    p1=Professor()
    print(Professor.mro())
    mro 查看继承顺序
    class Parentclass1:  #定义父类(基类或者超类)
        pass
    class Parentclass2: #定义父类
        pass
    class SubClass1(Parentclass1):  #单继承,基类是Parentclass1,派生类SubClass1
        pass                        #新建的类叫做派生类或者子类
    class SubClass2(Parentclass1,Parentclass2):  #多继承
        pass
    单继承和多继承 的说明
    #查看继承
    print(SubClass1.__bases__)  #__base__只查看从左到右继承的第一个子类,__bases__则是查看所有继承的父类
    print(SubClass2.__bases__)
    查看继承
    #继承和抽象
    #抽象最主要的作用是划分类别,抽象只是分析和设计的过程
    #继承:是基于抽象的结果,通过编程语言去实现它,
    # 肯定是先经历抽象这个过程,才能通过继承的方式去表达抽象的结构
    # 继承和重用性
    class Animal:
        def eat(self):
            print("%s 吃"%self.name)
        def drink(self):
            print("%s 喝"%self.name)
        def shit(self):
            print("%s 拉"%self.name)
        def pee(self):
            print("%s 撒"%self.name)
    
    class Cat(Animal):
    
        def __init__(self,name):
            self.name=name
            self.breed=""
    
        def cry(self):
            print("喵喵叫")
    class Dog(Animal):
    
        def __init__(self,name):
            self.name=name
            self.breed=""
    
        def cry(self):
            print("汪汪叫")
    ##########执行########
    c1=Cat("小白家的小黑猫")
    c1.eat()
    c2=Cat("小黑家的小白猫")
    c2.drink()
    d1=Dog("胖子家的小瘦狗")
    d1.eat()
    继承和重用性

     通过继承的方式新建类B,让B继承A,B会‘遗传’A的所有属性(数据属性和函数属性),实现代码重用

    class Animal:
        def __init__(self,name,aggressivity,life_value):
            self.name=name
            self.aggressivity=aggressivity
            self.life_value=life_value
    
        def eat(self):
            print("%s is eating"% self.name)
    class Dog(Animal):
        pass
    
    class Person(Animal):
        pass
    egg=Person("egon",10,1000)
    ha2=Dog("二愣子",50,1000)
    egg.eat()
    ha2.eat()
    代码的继承(人和狗的例子)

    派生(子类):

    class Animal:
        """
        人和狗都是动物所以创造一个Animal基类
        """
        def __init__(self,name,aggressivity,life_value):
            self.name=name    #人和狗都有自己的昵称
            self.aggressivity=aggressivity #人和狗都有自己的攻击力
            self.life_value=life_value #人和狗都有自己的生命值
    
        def eat(self):
            print("%s is eating"% self.name)
    
    class Dog(Animal):
        """
        狗类,继承Animal类
        """
        def bite(self,people):
            """
            派生:狗有咬人的技能y
            :param people:
            :return:
            """
            people.life_value-=self.aggressivity
    
    class Person(Animal):
        def attack(self,dog):
            """
            派生:人有攻击狗的技能
            :param dog:
            :return:
            """
            dog.life_value-=self.aggressivity
        pass
    egg=Person("egon",10,1000)
    ha2=Dog("二愣子",50,1000)
    print(ha2.life_value)
    egg.attack(ha2)
    print(ha2.life_value)
    派生的例子(人和狗)

    super:

    在python3中,子类执行父类的方法也可以直接用super方法.

    class A:
        def hahaha(self):
            print("A")
    class B(A):
        def hahaha(self):
            super().hahaha()
            #super(B,self).hahaha()
            #A.hahaha(self)
            print("B")
    a=A()
    b=B()
    b.hahaha()  #A B
    super(B,b).hahaha() #A
    子类继承父类的两种方法

    派生:

    class Animal:
        """
        人和狗都是动物所以创造一个Animal基类
        """
        def __init__(self,name,aggressivity,life_value):
            self.name=name    #人和狗都有自己的昵称
            self.aggressivity=aggressivity #人和狗都有自己的攻击力
            self.life_value=life_value #人和狗都有自己的生命值
    
        def eat(self):
            print("%s is eating"% self.name)
    #
    class Dog(Animal):
        """
        狗类,继承Animal类
        """
        def __init__(self,name,breed,aggressivity,life_value):
            super().__init__(name,aggressivity,life_value) #执行父类Animal的init方法
            self.breed=breed #派生出了新属性
        def bite(self,people):
            """
            派生:狗有咬人的技能y
            :param people:
            :return:
            """
            people.life_value-=self.aggressivity
        def eat(self):
            #Animal.eat(self)
            #super().eat()
            print("from Dog")
    
    class Person(Animal):
        """
        人类,继承Animal类
        """
        def __init__(self, name,aggressivity, life_value,money):
            #Animal.__init__(self,name,aggressivity,life_value)
            #super(Person,self).__init__(name,aggressivity,life_value)
            super().__init__(name, aggressivity, life_value)  # 执行父类Animal的init方法
            self.money = money  # 派生出了新属性
        def attack(self,dog):
            """
            派生:人有攻击狗的技能
            :param dog:
            :return:
            """
            dog.life_value-=self.aggressivity
        def eat(self):
            # super().eat()
            Animal.eat(self)
            print("from Person")
    
    egg=Person("egon",10,1000,600)
    ha2=Dog("二愣子","哈士奇",50,1000)
    print(egg.name)
    print(ha2.name)
    egg.eat()
    egg.attack(ha2)
    print(ha2.life_value)
    super 派生

    通过继承建立了派生类与基类之间的关系,它是一种'是'的关系,比如白马是马,人是动物。

    当类之间有很多相同的功能,提取这些共同的功能做成基类,用继承比较好,比如教授是老师

    class Teacher:
        def __init__(self,name,gender):
            self.name=name
            self.gender=gender
        def teach(self):
            print("teaching")
    class Professor(Teacher):
        pass
    p1=Professor("egon","male")
    p1.teach()
    # teaching

    (2)多态:

      一种事物的多种形态叫做多态

    class Animal:pass
    class Dog(Animal):pass
    class Cat(Animal):pass

    (3)鸭子类型:

      #对于某一些方法来说,可以无差别的对待几个类型就是鸭子类型

    #python 不崇尚数据类型之间的继承关系

      #数据类型之间减少依赖关系,解耦

    #写功能性的程序:以功能为导向

    #写框架类的,或者模块类的,使用继承的同时还要考虑解耦

    二、今日内容 :

    抽象类和接口类:

      (1)不崇尚接口类

      (2)python本身支持多继承,没有接口专用的语法,但是我知道接口的概念

    封装:

      (1)私有属性

      (2)将方法转换成属性的机制:@property

      (3)@classmethond @staticmethod

    1、接口类

    #接口类
    #继承有两种用途:
    # 一、继承基类的方法,并且做出自己的改变或者拓展(代码重用)
    #二、声明某个子类兼容于某基类,定义一个接口类interface,接口类中定义了一些接口名
    # (就是函数名)且并未实现接口的功能,子类继承接口类,并且实现接口中的功能

    最基础的接口类(但是容易出问题)
    class Alipay:
        """
        支付宝支付
        """
        def pay(self,money):
            print("支付宝支付了%s元"%money)
    
    class Applepay:
        """
        apple pay 支付
        """
        def pay(self,money):
            print("apple pay 支付了%s元"%money)
    
    def pay(payment,money):
        """支付函数,总体负责支付
        对应支付的对象和要支付的金额
        """
        payment.pay(money)
    
    p=Alipay()
    p1=Applepay()
    pay(p,200)  #支付宝支付了200元
    pay(p1,2000) #apple pay 支付了2000元

    接口初成:手动报异常

    class Payment:
        def pay(self):
            raise NotImplementedError
    class Wechatpay(Payment):
        def fuqian(self,money):
            print("微信支付了%s元"%money)
    p=Wechatpay()  #这里不报错
    pay(p,200)  #这里报错了

    接口编程:是依赖模板进行编程

    from abc import ABCMeta,abstractmethod
    #接口类,是规范子类的一个模板,只要接口类中定义的,就应该在子类中实现
    class Payment(metaclass=ABCMeta): #模板,接口类
        @abstractmethod   #装饰器接口类中的方法的,加上这个装饰器,自动检测子类中的方法名
        def pay(self,money):
            pass
        
    class Ali_Pay(Payment):
        def pay(self,money):
            print("您使用的支付宝支付了%s元"%money)
    class Apple_Pay(Payment):
        def pay(self,money):
            print("您使用的苹果支付了%s元"%money)
    class Wechat_Pay(Payment):
        def pay (self,money):
            print("微信支付了%s元"%money)
    
    def pay(obj,money):
        return obj.pay(money)
    
    # apple=Apple_Pay()
    # ali=Ali_Pay()
    wechat=Wechat_Pay()
    # pay(apple,100)  #apple.pay(100)
    pay(wechat,200) #微信支付了200元
    支付例子(依赖接口编程)
    from abc import ABCMeta,abstractmethod
    class Fly_Animal(metaclass=ABCMeta):
        @abstractmethod
        def fly(self):pass
    
    class Swim_Animal(metaclass=ABCMeta):
        @abstractmethod
        def swim(self):
            pass
    
    class Walk_Animal(metaclass=ABCMeta):
        @abstractmethod
        def walk(self):
            pass
    
    class Frog(Walk_Animal,Swim_Animal):
        def walk(self):
            print("实现walk功能")
    
    class Swan(Walk_Animal,Swim_Animal,Fly_Animal):pass
    class Bird(Swim_Animal,Fly_Animal):pass
    接口隔离原则

    接口隔离原则:使用多个专门的接口,而不使用单一的总接口,而客户端不应该依赖那些不需要的接口

    #一切皆文件
    import abc  #利用abc模块实现抽象类
    
    class All_file(metaclass=abc.ABCMeta):
        all_type="file"
        @abc.abstractmethod  #定义抽象方法,无序实现功能
        def read(self):
        # ‘子类必须定义读功能’
            pass
        @abc.abstractmethod  #定义抽象方法,无序实现功能
        def read(self):
        # ‘子类必须定义写功能’
            pass
    class Txt(All_file): #子类继承抽象类,但是必须定义read和write方法
        def read(self):
            print("文本数据的读取方法")
    
        def write(self):
            print("文本数据的读取方法")
    
    class Sata(All_file): #子类继承抽象类,但是必须定义read和write方法
        def read(self):
            print("硬盘数据的读取方法")
    
        def write(self):
            print("硬盘数据的读取方法")
    
    class Process(All_file): #子类继承抽象类,但是必须定义read和write方法
        def read(self):
            print("数据的读取方法")
    
        def write(self):
            print("进程数据的读取方法")
    wenbenwenjian=Txt()
    yingpanwenjian=Sata()
    jinchengwenjian=Process()
    #这样大家都是被归一化了,也就是一切皆文件的思想
    wenbenwenjian.read()
    yingpanwenjian.write()
    jinchengwenjian.write()
    
    print(wenbenwenjian.all_type)
    print(yingpanwenjian.all_type)
    print(jinchengwenjian.all_type)
    一切皆文件(抽象在python中的应用)

    总结:

    #接口类:

     (1)是规范子类的一个模板,只要接口类中定义的,就应该在子类中实现

     (2)接口类不能被实例化,它只能被继承

     (3)支持多继承

    #抽象类

      (1)模板  规范

      (2)抽象类可以实现一些子类共有的功能和属性抽象类不鼓励多继承

        文件操作:打开文件、关闭文件、写文件、读文件

        硬盘操作:打开、关闭、读、写

        进程文件:打开 关闭、读、写

       (3)python没有接口概念,只能借助抽象类模块来实现接口类

        接口————java:没有多继承 Interface

    文件的抽象化

    from abc import ABCMeta,abstractmethod
    class Base(metaclass=ABCMeta):
        def __init__(self,filename):
            self.filename=filename
            @abstractmethod  #抽象方法
            def open(self):
                return "file_handler"
            
            @abstractmethod
            def close(self):pass
    
            @abstractmethod
            def read(self): pass
    
            @abstractmethod
            def write(self): pass
    
    class File(Base):
        def open(self):pass
        def close(self):pass
        def read(self):pass
        def write(self):pass
    文件的打开关闭读写

    2、封装

      封装:把一些实行和方法放在类里,这本身就是一种封装

      #封装:把属性和方法藏在类里,我只能在类内部调用,不能在外部使用

     (1)私有变量 

    #其实这仅仅这是一种变形操作
    #类内所有双下划线开头的名称如:__x都会自动变形成:_类名__x的形式:
    class 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是可以访问到的,即这种操作并不是严格意义上的限制外部访问
        #仅仅只是一种语法意义上的变形
    私有变量

    调用类内的私有静态属性

    class Dog:
        __role="dog"  #私有的静态属性
        def func(self):
            print(Dog.__role)  #_类__名字
    print(Dog.__dict__)
    # print(Dog._Dog__role)  #不能这么调用
    #从类的外面不能直接调用,在类内的使用加上了一层密码:_类名
    d=Dog()
    d.func()
    调用类内的私有静态属性

    私有的方法

    class Dog:
        __role="dog"   #私有的属性
        def __discount(self):  #私有的方法
            print("in__func")
    
        def price(self):
            self.__discount()
    私有的方法

    总结:定义一个私有变量属性方法:__名字

      在类内部可以直接用:__名字

      在类的外部不能直接使用,如果一定要用,在私有方法之前加上:_类名,变成_类名__名字

      在类外的名字 通过__dict__就可以查看

    例子:不需要的可以隐藏

    class Room:
        def __init__(self,name,price,length,width):
            self.name=name
            self.price=price
            self.__length=length
            self.__width=width    #隐藏的长与宽
        def area(self):
            return self.__width*self.__length  
    house=Room("小明",1000,22,33)
    print(house.area())
    例子:房子的面积(隐藏长与宽)

       私有的不能被继承

    class A:
        def __func(self):
            print("__a_func")   #_A__func
    class B(A):
        def __init__(self):
            self.func()      #_B__func
    b=B()

    结果报错

    总结:私有的静态属性、方法、对象属性

        #使用__名字的方式调用,保证在类内部可以调用,外部不行

        #私有的不能被继承

        #当有一个名字。不想被外部使用,也不想被子类继承,只想在内部使用的时候就定义私有的

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

    例一:BMI指数(bmi是计算而来的,但很明显它听起来像是一个属性而非方法,如果我们将其做成一个属性,更便于理解)
    
    成人的BMI数值:
    过轻:低于18.5
    正常:18.5-23.9
    过重:24-27
    肥胖:28-32
    非常肥胖, 高于32
      体质指数(BMI)=体重(kg)÷身高^2(m)
      EX:70kg÷(1.75×1.75)=22.86
    例子,题目说明
    class Person:
        def __init__(self,name,height,weigth):
            self.name=name
            self.height=height
            self.weight=weigth
    
        def bmi(self):
            return self.weight/(self.height**2)
    li= Person("",1.66,51)
    print(li.bmi())
    解释例子

    #1)属性的值,是这个方法的返回值

    #2)这个方法不能有参数

    园的周长的例子:

    import math
    class Circle:
        def __init__(self,radius): #圆的半径radius
            self.radius=radius
    
        @property
        def area(self):
            return math.pi * self.radius**2 #计算面积
    
        @property
        def perimeter(self):
            return 2*math.pi*self.radius #计算周长
    
    c=Circle(10)
    print(c.radius)
    print(c.area) #可以向访问数据属性一样去访问area,会触发一个函数的执行,动态计算出一个值
    print(c.perimeter) #同上
    '''
    输出结果:
    314.1592653589793
    62.83185307179586
    '''
    圆的周长和面积
    #注意:此时的特性area和perimeter不能被赋值
    c.area=3 #为特性area赋值
    '''
    抛出异常:
    AttributeError: can't set attribute
    '''
    

     超市打折的例子:  修改原价,隐藏原价价格

    class Goods:
        __discount=0.8  #静态属性
        def __init__(self,name,price):
            self.name=name
            self.price=price  #原价
    
        @property
        def price(self):   #折后价
            return self.__price*Goods.__discount
    
        @price.setter     #只能传一个参数
        def price(self,new_price):  #修改原价
            self.__price=new_price
            if type(new_price) is int:   #座一次限制后,下面的价格修改就会变得安全
                self.__price=new_price
    
    apple=Goods("苹果",10)
    print(apple.price)
    danana=Goods("香蕉",2.5)
    print(danana.price)
    apple.price=5
    print(apple.price)
    超市打折的例子

    总结:  封装

      #__私有+property

      #让对象的属性变得更安全了

      #获取到的对象的值可以进行一些加工

      #修改对象的值的同时可以进行一些验证

    补充:  setter和  property

    class Foo:
        @property
        def AAA(self):
            print("get的时候运行我啊")
        @AAA.setter
        def AAA(self,value):
            print("set的时候运行我啊")
    
        @AAA.deleter
        def AAA(self):
            print("delete的时候运行我啊")
    #只有在属性AAA定义property后才能定义AAA.setter,AAA.deleter
    f1=Foo()
    f1.AAA
    f1.AAA="aaa"
    del f1.AAA

    怎么用:

    class Goods:
    
        def __init__(self):
            # 原价
            self.original_price = 100
            # 折扣
            self.discount = 0.8
    
        @property
        def price(self):
            # 实际价格 = 原价 * 折扣
            new_price = self.original_price * self.discount
            return new_price
    
        @price.setter
        def price(self, value):
            self.original_price = value
    
        @price.deleter
        def price(self):
            del self.original_price
    
    
    obj = Goods()
    obj.price         # 获取商品价格
    obj.price = 200   # 修改商品原价
    print(obj.price)
    del obj.price     # 删除商品原价

    关于删除:

    class Goods:
        __discount=0.8
        def __init__(self,name,price):
            self.__name=name
            self.__price=price
    
        @property
        def name(self):
            return self.__name
    
        @name.setter
        def name(self,new_name):
            self.__name=new_name
    
        @name.deleter
        def name(self):
            del self.__name
    
        @property
        def price(self):
           return self.__price*Goods.__discount
    
        @price.setter
        def price(self,new_price):
            if type(new_price)is int:
                self.__price=new_price
    apple=Goods("苹果",10)
    # del apple.name
    print(apple.name)
    删除售卖的品种

    (3)类方法

      @classmethod

    class Goods:
        __discount=0.8
        @classmethod #类方法
        def change_discount(cls,new_discount):
            cls.__discount=new_discount*0.5
    
        @classmethod
        def get_discount(cls):
            return cls.__discount
    # apple=Goods()
    Goods.change_discount(0.75)
    print(Goods.get_discount())

    总结:

      类方法: 

        #调用:不需要实例化,直接用类名调用就好

        #定义:不用接受self参数,默认传cls,cls就代表当前方法所在的类

      #什么时候用类方法?

      #需要使用静态变量 且不需要和对象相关的任何操作 就使用静态方法

    (4)静态方法

          @staticmethod

    class A:
        @staticmethod
        def func(name):
            print(123)
    A.func("alex")

    总结:面向对象的编程:专门为面向对象编程提供的一个方法————staticmethod

      #它完全可以当做普通的函数去用,只不过这个函数需要通过类名.函数名调用

      #其他 传参 返回值 完全没有区别

    绑定和非绑定:

    class A:
        @staticmethod
        def func1(name):
            print(123)
    
        @classmethod
        def func2(name):
            print(123)
    
        def func3(self):pass
    a=A()
    print(a.func1)  #静态方法
    print(a.func2)  #类方法:找到绑定到A类的func
    print(a.func3)  #普通方法:绑定到A类对想的func

    在类里面,一共可以定义这三种方法:

      普通方法 self

      类方法 cls   @classmrthod

      静态方法  @staticmethod

    静态方法和类方法都是直接使用类名调用

    普通方法:对象调用

  • 相关阅读:
    垃圾收集器
    垃圾收集算法
    JVM内存模型
    工厂方法模式
    类加载机制
    六大设计原则
    单例模式
    HFish开源蜜罐搭建
    利用metasploit复现永恒之蓝
    零信任网络初识
  • 原文地址:https://www.cnblogs.com/number1994/p/8092988.html
Copyright © 2020-2023  润新知