zoukankan      html  css  js  c++  java
  • 面向对象02 继承

    • 继承 :解决代码的重复

      #继承语法 class 子类名(父类名):pass
      class A:
          pass
      class B(A):
          pass
      
      # A 父类 基类 超类
      # B子类 派生类
      
      • 子类可以使用父类中的 : 方法和静态变量

        class Animal:
            def __init__(self,name):
                self.name = name
            def eat(self):
                print('%s is eating'%self.name)
            def drink(self):
                print('%s is drinking'%self.name)
            def sleep(self):
                print('%s is sleeping'%self.name)
        class Cat(Animal):
            def climb_tree(self):
                print('%s is climbing'%self.name)
        
        class Dog(Animal):
            def house_keep(self):
                print('%s house keeping'%self.name)
        
        小白 = Cat('小白')
            # 先开辟空间,空间里有一个类指针-->指向Cat
            # 调用init,对象在自己的空间中找init没找到,到Cat类中找init也没找到,
            # 找父类Animal中的init
        小白.eat()#小白 is eating
        小白.climb_tree()#小白 is climbing
        小黑 = Dog('小黑')
        小黑.eat()#小黑 is eating
        
      • 当子类和父类的方法重名的时候,我们只使用子类的方法,而不会去调用父类的方法了

        class Animal:
            def __init__(self,name):
                self.name = name
            def eat(self):
                print('%s is eating'%self.name)
            def drink(self):
                print('%s is drinking'%self.name)
            def sleep(self):
                print('%s is sleeping'%self.name)
        
        class Cat(Animal):
            def eat(self):
                print('%s吃猫粮'%self.name)
        
            def climb_tree(self):
                print('%s is climbing'%self.name)
        
        小白 = Cat('小白')
        小白.eat()#小白吃猫粮
        
      • 子类想要调用父类的方法的同时还想执行自己的同名方法

        • 在子类的方法中调用父类的方法 :父类名.方法名(self)

          class Animal:
              def __init__(self,name,food):
                  self.name = name
                  self.food = food
                  self.blood = 100
                  self.waise = 100
              def eat(self):
                  print('%s is eating %s'%(self.name,self.food))
              def drink(self):
                  print('%s is drinking'%self.name)
              def sleep(self):
                  print('%s is sleeping'%self.name)
          
          class Cat(Animal):
              def eat(self):
                  self.blood += 100
                  Animal.eat(self)
              def climb_tree(self):
                  print('%s is climbing'%self.name)
                  self.drink()
          
          class Dog(Animal):
              def eat(self):
                  self.waise += 100
                  Animal.eat(self)
              def house_keep(self):
                  print('%s is keeping the house'%self.name)
          小白 = Cat('小白','猫粮')
          小黑 = Dog('小黑','狗粮')
          小白.eat()#小白 is eating 猫粮
          小黑.eat()#小黑 is eating 狗粮
          print(小白.__dict__)#{'name': '小白', 'food': '猫粮', 'blood': 200, 'waise': 100}
          print(小黑.__dict__)#{'name': '小黑', 'food': '狗粮', 'blood': 100, 'waise': 200}
          
          #父类和子类方法的选择:
          # 子类的对象,如果去调用方法
          # 永远优先调用自己的
              # 如果自己有 用自己的
              # 自己没有 用父类的
              # 如果自己有 还想用父类的 : 直接在子类方法中调父类的方法 父类名.方法名(self)
          
    • 单继承

      # 单继承
      # 调子类的 : 子类自己有的时候
      # 调父类的 : 子类自己没有的时候
      # 调子类和父类的 :子类父类都有,在子类中调用父类的
      class D:
          def func(self):
              print('in D')
      class C(D):pass
      class A(C):
          def func(self):
              print('in A')
      class B(A):pass
      B().func()
      
    • 多继承

      • 有一些语言不支持多继承 比如 java
      • python语言的特点 : 可以在面向对象中支持多继承
      # 多继承
      # 一个类有多个父类,在调用父类方法的时候,按照继承顺序,先继承的就先寻找
      class D:
          def func(self):
              print('in D')
      class C(D):pass
      class A(C):
          def func(self):
              print('in A')
      class B(A):pass
      B().func()
      
    • object类 类祖宗

      • 所有在python3当中的类都是继承object类的

        class A:pass
        print(A.__bases__)#(<class 'object'>,)
        class C:pass
        class B(A,C):pass
        print(B.__bases__)#(<class '__main__.A'>, <class '__main__.C'>)只能找到父类 不能找到父类的父类
        
    • 绑定方法和普通的函数
      from types import FunctionType,MethodType
      # FunctionType : 函数
      # MethodType : 方法
      class A:
          def func(self):
              print('in func')
      
      print(A.func)  # 函数 #<function A.func at 0x000002841C479488>
      a = A()
      print(a.func)  # 方法 #<bound method A.func of <__main__.A object at 0x000002841C308240>>
      print(isinstance(a.func,FunctionType))#False
      print(isinstance(a.func,MethodType))#True
      print(isinstance(A.func,FunctionType))#True
      print(isinstance(A.func,MethodType))#False
      
      #类.func是函数
      #对象.func是方法
      
    • pickel 可以序列化对象

      • 前提py文件里有对象的类

        class Course:
            def __init__(self,name,period,price):
                self.name = name
                self.period = period
                self.price = price
        
        python = Course('python','6 moneth',21800)
        linux = Course('linux','5 moneth',19800)
        go = Course('go','4 moneth',12800)
        import  pickle
        with open('pickle_file','ab') as f:
            pickle.dump(linux,f)
            pickle.dump(go,f)
        with open('pickle_file','rb') as f:
            while True:
                try:
                    obj = pickle.load(f)
                    print(obj.name,obj.period)
                except EOFError:
                    break
        
        

    继承进阶

    类 的继承

    多继承

    • 只要继承object类就是新式类
    • 不继承object类的都是经典类

    在python3中 所有的类都继承object类,都是新式类

    在python2中 不继承object的类都是经典类,继承object类的就是新式类了

    经典类:在py3中不存是,在py2中不主动继承object的类

    在py2中
    class A:pass   #经典类
    class B(object):pass#新式类
    
    在py3中
    class A:  #pass #新式类
    class B(object):pass #新式类
    

    在单继承方面(无论是新式类还是经典类都是一样的)

    class A:
        def func(self):pass
    class B(A):
        def func(self):pass
    class C(B):
        def func(self):pass
    class D(c):
        def func(self):pass
    d = D()
    
    寻找某一个方法的顺序:D->C->B->A
    越往父类走,是深度
    

    多继承

    class A:
        def func(self):
            print('A')
    class B(A):
        def func(self):
            print('B')
    class C(A):
        def func(Self):
            print(C)
    class D(B,C):
        def func(self):
            print('B')
    print(D.mro()) #只在新式类中有,经典类没有
    d = D()
    d.func()
    在走到一个点,下一个点既可以深度走,也可以从广度走的时候,总是先走广度,再走深度,广度优先
    在经典类总,都是深度优先,总是在一条路走不通之后再换一条路,走过的点不会再走了
    

    C3算法

    算法内容:

    1. 如果是单继承 那么总是按照从子类->父类的顺序来计算查找顺序
    2. 如果是多继承 需要按照自己本类,父类1的继承顺序,父类2的继承顺序
    3. merge的规则:如果一个类出现在从左到右所有顺序的最左侧,并没有在其他位置出现,那么先提出了作为继承顺序中的一个 或 一个类出现在从左到右顺序的最左侧,并没有在其他顺序出现那么先提出了作为继承顺序中的第一个
    4. 如果从左到右第一个顺序中的第一个类出现在后面且不是第一个,那么不能提取,顺序向后继续找其他顺序中父类上述条件的类
    • super — 是按照mro顺序来寻找当前类的下一个父类的 (与mro方法的关系)
    1. 在python3中不需要传参数,自动就帮我们寻找当前类的mro顺序的下一个类中的同名方法

    2. 在python2中的新式类中,需要我们主动传递参数 super(子类的名字和子类的对象.函数名(),这样才能够帮我们调用到这个子类的mre顺序的下一个类中的方法

      在python2中的经典类中,并不支持使用super来找下一个类

      class A(object):
          def func(self):print('A')
      class B(A):
          def func(self):
              super().func()
              print('B')
      class C(A):
          def func(self):
              super().func()
              print('C')
      class D(B,C):
          def func(self):
              super().func()
              print('D')
      D().func()
      '''
      A
      C
      B
      D
      
      '''
      
    3. 其中 super().func() 也可以写成 super(D,self).func()

    4. 在单继承的程序中,super就是找父类:

      class User:
          def __init__(self,name):
              self.name = name
      class VIPUser(User):
          def __init__(self,name,level,strat_date,end_date):
              # User.__init__(self,name)
              # super().__init__(name)              # 推荐的
              # super(VIPUser,self).__init__(name)
              self.level = level
              self.strat_date = strat_date
              self.end_date = end_date
              
       '''
       解析:中间的# 的三种方式功能都是找到并执行父类中的__init__的方法,推荐使用
       super().__init__(name)。
       '''
      
          先找每个类的继承关系(注意因为加载顺序的缘故从,上至下开始寻找)
      
          A(0) = [AO]		# A 继承于object类 
      
          B(A) = [BAO]	     # B继承于A类
      
          C(A) = [CAO]	    # C继承于A类
      
          D(B) = [DBAO]	   # D继承于B类
      
          E(C) = [ECAO]	   # E继承于C类
      
          那么算法为:
      
          F(D,E) = merge(D(B)+E(C))
      
          ​	= [F] + [DBAO] + [ECAO]
      
          F = [DBAO] + [ECAO]
      
          FD = [BAO] + [ECAO]
      
          FDB = [AO] + [ECAO]
      
          FDBE = [AO] + [CAO]
      
          FDBEC = [AO] + [AO]	
      
          FDBECAO
      
        - **使用子类名.mro() 查看继承顺序**
      
          只有新式类中有,经典类没有的。
      
      1. 通过继承实现的类的开发规范
    5. 父类对子类的约束

      1. 普通类 如 class A B C等等

      2. 抽象类

        • 是一个开发的规范,约束他的所有子类必须实现一些和他同名的方法

        引入:例:不同付款方式付款

        class Wechat():
            def __init__(self,name):
                self.name = name
            def pay(self,money):
            	print('%s通过微信支付%s钱成功'%(self.name,money))
                
        class Alipay():
            def __init__(self,name):
                self.name = name
            def pay(self,money):
                print('%s通过微信支付%s钱成功'%(self.name,money))
                
        class Apple(Payment):
            def __init__(self,name):
                self.name = name
            def pay(self,money):
                dic = {'name': self.name, 'number': money}
                # 想办法调用苹果支付 url连接 把dic传过去
                print('%s通过苹果支付%s钱成功' % (self.name, money))
                
        aw = WeChat('alex')
        aw.pay(400)
        aa = Alipay('alex')
        aa.pay(400)
        '''
        这样我们通过创建了2个对象,然后调用类中的方法pay,把钱传入完成支付的功能
        '''
        

        当然我们有时需要归一化设计:

        def pay(name,price,kind):
            if kind == 'Wechat':
                obj = WeChat(name)
            elif kind == 'Alipay':
                obj = Alipay(name)
            elif kind == 'Apple':
                obj = Apple(name)
            obj.pay(price)
        pay('alex',400,'Wechat')
        pay('alex',400,'Alipay')
        pay('alex',400,'Apple')
        '''
        我们通过定义一个函数,通过判别传入的kind参数,选择创建实例化name对象,然后调用方法,完成付款。
        '''
        

        注意:完成上述需求需要三个类中的pay的方法名一样如果不一样就会报错。

        为解决上述问题引入了抽象类对子类进行相关的约束

        class Payment:
        	def pay(self,money):
                raise NotImplementedError('请在子类中重写同名pay方法')
        class Alipay(Payment):pass
        class WeChat(Payment):pass    
        class Apple(Payment): pass
        def pay(name,price,kind):
            if kind == 'Wechat':
                obj = WeChat(name)
            elif kind == 'Alipay':
                obj = Alipay(name)
            elif kind == 'Apple':
                obj = Apple(name)
            obj.pay(price)
        '''
        解析:我们创建一个所有类的父类,定义一个pay的方法,如果执行,则抛出异常。
        当我们执行pay函数时,我们会调用方法 pay ,当对象中没有pay的方法时,就会去父类Payment中调用,所以抛出异常。所以加入抽象类约束我们子类中方法名称一致。
        
        '''
        
        
        # 另一种方式:依赖于abc 模块
        from abc import ABCMeta,abstractmethod
        class Payment(metaclass=ABCMeta):
            @abstractmethod
            def pay(self,money):
                '''只要你见到了项目中有这种类,你要知道你的子类中必须实现和pay同名的方法'''
                raise NotImplementedError('请在子类中重写同名pay方法')
         
        # 一旦子类中没有pay方法,实例化都无法完成。
        方式特点:约束力强。缺点:依赖于abc模块
        
        
    6. 多态

      1. python中处处是多态,一切皆对象

      2. 什么是多态,借助java讲解

        一个类型表现出来的多种状态

        在Java中:一个参数必须指定类型,所以如果想让俩个类型的对象都可以传,那么必须让这俩个类继承自一个父类,再指定类型的时候使用父类来指定

      3. 鸭子类型

        class list:
            def __len__(self):pass
        class dict:
            def __len__(self): pass
        class set:
            def __len__(self): pass
        class tuple:
            def __len__(self): pass
        class str:
            def __len__(self): pass
        def len(obj):
            return obj.__len__()
        # 如上述所有实现了__len__方法的类,在调用len函数的时候,obj都说是鸭子类型。
        # 再如:迭代器协议 __iter__ __next__ 是迭代器。即所有的迭代器都是鸭子类型
        
  • 相关阅读:
    Pytorch笔记
    Anaconda使用
    最大流最小割算法
    pycallgraph--使用pycallgraph绘制Python函数调用关系图
    论文表格--三线表
    0514数据结构--递归、排序和查找
    0511操作系统
    0510操作系统
    ACWING算法提高课-动态规划
    删括号
  • 原文地址:https://www.cnblogs.com/lianzibing/p/10993648.html
Copyright © 2011-2022 走看看