zoukankan      html  css  js  c++  java
  • python之路 -- 面向对象基础2

    面向对象的三大特征

      ——继承,多态,封装

    继承

    继承是一种创建新类的方式,在python中新建的类可以继承一个或多个父类,父类又可称为基类或超类,新建的类称为派生类或子类

     python中类的继承分为:单继承和多继承

    class ParentClass1: #定义父类
        pass
    
    class ParentClass2: #定义父类
        pass
    
    class SubClass1(ParentClass1): #单继承,基类是ParentClass1,派生类是SubClass
        pass
    
    class SubClass2(ParentClass1,ParentClass2): #python支持多继承,用逗号分隔开多个继承的类
        pass

     查看继承

    >>> SubClass1.__bases__ #__base__只查看从左到右继承的第一个子类,__bases__则是查看所有继承的父类
    (<class '__main__.ParentClass1'>,)
    >>> SubClass2.__bases__
    (<class '__main__.ParentClass1'>, <class '__main__.ParentClass2'>)

    提示:如果没有指定基类,python的类会默认继承object类,object是所有python类的父类

      猫可以:喵喵叫、吃、喝、拉、撒
    
      狗可以:汪汪叫、吃、喝、拉、撒
    
    如果我们要分别为猫和狗创建一个类,那么就需要为 猫 和 狗 实现他们所有的功能,伪代码如下:
    #继承的代码实现
    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()
    
    #输出结果为:
    #小白家的小黑猫 吃 

    子类也可以添加自己新的属性或者在自己这里重新定义这些属性(不会影响到父类)
    需要注意的是,一旦重新定义了自己的属性且与父类重名,那么调用新增的属性时,就以自己为准了。(也就是重写父类方法)
    所谓重写,就是子类中,有一个和父类相同名字的方法,在子类中的方法会覆盖掉父类中同名的方法

    新式类和经典类

    # python2.7 新式类和经典类共存,新式类要继承object
    # python3中所有类都是新式类,python3中的类默认继承object
        ——新式类继承顺序广度优先
        ——经典类继承顺序深度优先
    # 经典类和新式类还有一个区别  mro方法只在新式类中存在

    继承顺序问题

     1 class F:
     2     def func(self):
     3         print('F')
     4 class A(F):
     5     def func(self):
     6         print('A')
     7 class B(A):pass
     8     # def func(self):
     9     #     print('B')
    10 class E(F):
    11     def func(self):
    12         print('E')
    13 class C(E):
    14     def func(self):
    15         print('C')
    16 class D(B,C):
    17     pass
    18     # def func(self):print('D')
    19 
    20 d = D()
    21 d.func()    #输出的结果为:A
    22 print(D.mro())  #打印D的继承关系

     

    图一的继承顺序为:
    D->B->A->C->E->F
    图二的继承顺序为:
    D->B->A->F->C->E

    # 只要是子类的对象调用,子类中有的名字 一定用子类的,子类中没有才找父类的,如果父类也没有报错
    # 如果父类 子类都有 用子类的
        # 如果还想用父类的,单独调用父类的:
        #       父类名.方法名 需要自己传self参数
        #       super().方法名 不需要自己传self
    

     super的使用

     1 class Animal:
     2     def __init__(self,name,aggr,hp):
     3         self.name = name
     4         self.aggr = aggr
     5         self.hp = hp
     6     def eat(self):
     7         print('吃药回血')
     8         self.hp+=100
     9 
    10 class Dog(Animal):
    11     def __init__(self,name,aggr,hp,kind):
    12         super().__init__(name,aggr,hp)  #<==>Animal.__init__(self,name,aggr,hp)
    13         self.kind = kind       # 派生属性
    14     def eat(self):print('dog eating')
    15 
    16 jin = Dog('狗',200,500,'teddy')
    17 print(jin.name)
    18 jin.eat()
    19 super(Dog,jin).eat()  在外部使用super的时候需要传类和对象

    super的查找顺序和继承顺序相同
    #super 只在python3中存在
     super的本质 :不是单纯找父类 而是根据调用者的节点位置的广度优先顺序来的

     

     1 class A():
     2     def func(self): print('A')
     3 
     4 class B(A):
     5     def func(self):
     6         super().func()
     7         print('B')
     8 
     9 class C(A):
    10     def func(self):
    11         super().func()
    12         print('C')
    13 
    14 class D(B,C):
    15     def func(self):
    16         super().func()    
    17         print('D')
    18 #super的查找顺序和继承顺序相同
    19 d = D()
    20 d.func()    #输出结果为:A C B D
    21 print(D.mro())    #D->B->C->A

    接口类

    python中没有接口类,只是可以实现一个有接口类功能的类9(有抽象类)

    继承有两种用途:

    一:继承基类的方法,并且做出自己的改变或者扩展(代码重用)

    二:声明某个子类兼容于某基类,定义一个接口类Interface,接口类中定义了一些接口名(就是函数名)且并未实现接口的功能,子类继承接口类,并且实现接口中的功能

     1 class Alipay:
     2     '''
     3     支付宝支付
     4     '''
     5     def pay(self,money):
     6         print('支付宝支付了%s元'%money)
     7 
     8 class Applepay:
     9     '''
    10     apple pay支付
    11     '''
    12     def pay(self,money):
    13         print('apple pay支付了%s元'%money)
    14 
    15 
    16 def pay(payment,money):
    17     '''
    18     支付函数,总体负责支付
    19     对应支付的对象和要支付的金额
    20     '''
    21     payment.pay(money)
    22 
    23 
    24 p = Alipay()
    25 pay(p,200)    #支付宝支付了200元

    接口类的多继承

     1 #接口类的多继承
     2 #tiger 走路 游泳
     3 #swan 走路 游泳 飞
     4 #oldying 走路 飞
     5 from abc import abstractmethod,ABCMeta    #1.引用这个模块
     6 class Swim_Animal(metaclass=ABCMeta):     #2.传入这个metaclass=ABCMeta
     7     @abstractmethod                       #3.加上此装饰器的语法糖@abstractmethod
     8     def swim(self):pass                   #满足这3点的就可以成为接口类
     9 
    10 class Walk_Animal(metaclass=ABCMeta):
    11     @abstractmethod
    12     def walk(self):pass
    13 
    14 class Fly_Animal(metaclass=ABCMeta):
    15     @abstractmethod
    16     def fly(self):pass
    17 
    18 class Tiger(Walk_Animal,Swim_Animal):
    19     def walk(self):
    20         pass
    21     def swim(self):
    22         pass
    23 
    24 class OldYing(Fly_Animal,Walk_Animal):pass
    25 class Swan(Swim_Animal,Walk_Animal,Fly_Animal):pass
    接口类的多继承
     1 from abc import ABCMeta,abstractmethod
     2 
     3 class Payment(metaclass=ABCMeta):
     4     @abstractmethod
     5     def pay(money):
     6         print("支付了%s" % money)
     7 
     8 class Wechatpay(Payment):
     9     def fuqian(money):
    10         print('微信支付了%s元'%money)
    11 
    12 # p = Wechatpay(200) #此处实例化会报错
    13 #只实例化一个类,不调用类中的方法就会报错
    14 
    15 p = Wechatpay.fuqian(200)
    16 p2 = Wechatpay.pay(100)
    17 p3 = Payment.pay(50)
    18 #执行结果:
    19 #微信支付了200元
    20 #支付了100
    21 #支付了50
     

     抽象类

    与java一样,python也有抽象类的概念但是同样需要借助模块实现,抽象类是一个特殊的类,它的特殊之处在于只能被继承,不能被实例化
    抽象类与普通类的不同之处在于:抽象类中有抽象方法,该类不能被实例化,只能被继承,且子类必须实现抽象方法。这一点与接口有点类似,但其实是不同的,
    python支持抽象类,多继承。

    抽象类可以有构造方法,接口不能有构造方法;

    多态

    多态指的是一类事物有多种形态

     1 import abc
     2 class File(metaclass=abc.ABCMeta): #同一类事物:文件
     3     @abc.abstractmethod
     4     def click(self):
     5         pass
     6 
     7 class Text(File): #文件的形态之一:文本文件
     8     def click(self):
     9         print('open file')
    10 
    11 class ExeFile(File): #文件的形态之二:可执行文件
    12     def click(self):
    13         print('execute file')
    14 
    15 多态动态绑定(在继承的背景下使用时,有时也称为多态性)
    16 多态性是指在不考虑实例类型的情况下使用实例

    鸭子类型
    所谓鸭子类型,定义是‘是动态类型的一种风格‘。一个对象的特征不是由父类决定,而是通过对象的方法决定的。

    封装

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

     1 class Person:
     2     __key = 123  # 私有静态属性
     3     def __init__(self,name,passwd):
     4         self.name = name
     5         self.__passwd = passwd   # 私有属性
     6 
     7     def __get_pwd(self):         # 私有方法
     8         return self.__passwd   #只要在类的内部使用私有属性,就会自动的带上_类名
     9 
    10     def login(self):          # 正常的方法调用私有的方法
    11         self.__get_pwd()
    12 
    13 alex = Person('alex','alex3714')
    14 print(alex._Person__passwd)   # _类名__属性名(在内的外部只能通过这种方式调用私有属性和方法)
    15 print(alex.get_pwd())        #此处的调用方法会报错

     会用到私有的这个概念的场景

    1.隐藏起一个属性 不想让类的外部调用

    2.我想保护这个属性,不想让属性随意被改变

    3.我想保护这个属性,不被子类继承

  • 相关阅读:
    Java实现 LeetCode 343 整数拆分(动态规划入门经典)
    Java实现 LeetCode 342 4的幂
    Java实现 LeetCode 342 4的幂
    Java实现 LeetCode 342 4的幂
    Java实现 LeetCode 341 扁平化嵌套列表迭代器
    Java实现 LeetCode 341 扁平化嵌套列表迭代器
    Java实现 LeetCode 341 扁平化嵌套列表迭代器
    Java实现 LeetCode 338 比特位计数
    H264(NAL简介与I帧判断)
    分享一段H264视频和AAC音频的RTP封包代码
  • 原文地址:https://www.cnblogs.com/aberwang/p/9329398.html
Copyright © 2011-2022 走看看