zoukankan      html  css  js  c++  java
  • Python-面向对象之多继承

    1、Python不同版本的类

      Python2.2之前类是没有共同的祖先的,之后,引入object类,它是所有类的共同祖先类object。

      Python2 中为了兼容 ,分为古典类,新式类。

      Python2 中全部都是新式诶

      新式类都是继承自object的,新式类可以使用super

        

      Python2.2
      新式类:等同 python3,
       旧式类:不能使用super,只能使用 类名. 调用父类的方法属性, 没有base,只有bases
      Python3.x
      对2的统一, 一切都继承自 object,3 更像面向对象

      dir:尽量收集一个对象所有属性:dir(A):所有属性的列表
      
     1 In [4]: dir(A)
     2 Out[4]:
     3 ['__class__',
     4  '__delattr__',
     5  '__dict__',
     6  '__dir__',
     7  '__doc__',
     8  '__eq__',
     9  '__format__',
    10  '__ge__',
    11  '__getattribute__',
    12  '__gt__',
    13  '__hash__',
    14  '__init__',
    15  '__init_subclass__',
    16  '__le__',
    17  '__lt__',
    18  '__module__',
    19  '__ne__',
    20  '__new__',
    21  '__reduce__',
    22  '__reduce_ex__',
    23  '__repr__',
    24  '__setattr__',
    25  '__sizeof__',
    26  '__str__',
    27  '__subclasshook__',
    28  '__weakref__']
    29 
    30 In [5]:
    dir(A)

     2、多继承
      ocp原则:多用继承,少修改

      继承的用途:在子类上实现对基类的增强,实现多态

      多态:

         在面向对象中,父类,子类通过继承联系 在一起,如果可以通过一套方法,就可以实现不同表现,就是多态。

        一个类继承自多个类就是多继承,它将有多个类的特征

        多态必须建立在 继承和 覆盖才会体现!

     3、多继承弊端

      多继承很好的模拟了世界,但是会引起复杂性,带来冲突。多继承的实现会导致编译器设计的复杂度增加,所以现在很多语言舍弃了类的多继承。

      C++支持多继承, java舍弃多继承

      多继承可能会带来二义性。如:猫,狗继承了动物类的叫,但是子类继承谁的shout呢?

      解决方案:实现多继承的语言,要解决二义性,深度优先还是广度优先

     

                                   图1

     

                                    图2


                                            图3

    Python 有三套解决方案:
    2.2 早期:图2, 图3
    经典算法,深度优先 如截图2,c 离得近,但是没法使用,只能先用A的X,但是新式类后来修改后,只保留重复的最后一个
    即 M D B C A object
    继承的单调性 不能保证
    2.3版本解决了上面的问题:
    C3 算法,并不是真正的 深度优先,可以检测有没有冲突性,单调性如果有二义性会抛异常

    先看一下MRO 就明白搜索顺序了,以后多看看继承路径!(方法 属性都是一样的查找顺序)

    因为动态语言,所以编译时才可能发现问题,此时已经晚了!!!,所以宁愿使用单继承,少使用多继承
            
           C3算法解决了多继承的二义性


      经典算法有很大的问题,如果C 中有覆盖A的方法,就不会访问到了,因为先访问A
      新式算法,还是深度优先,解决了重复问题,但是没有解决继承的单调性
      c3算法,解决了继承的单调性,它阻止了之前版本产生二义性的代码,求得MRO本质是为了线性化,且确定了顺序。

      MRO:方法解析顺序

    3、多继承的缺点:
      当类很多,继承复杂的情况下,继承路径太多,很难说清什么样的继承路径
      Python语法允许多继承,但Python代码时解释执行,只有执行到的时候,才会发现错误,此时已经晚了。
      不管语言是够支持多继承,都应避免多继承。
       Python的面向对象太灵活,太开放,所以要团队协作。

    4、 Mixin混合功能:
      类有下面的继承关系:

              Pdf --------> Document <--------Word
      文档Document类是其他所有文档类的抽象基类:
      Word,Pdf类是Document的子类
      
      思路:

      1、需求为Document子类提供打印能力
    1 class Document:
    2     def __init__(self, content):
    3         self.content = content
    4 
    5     def print(self):# 没有实现,完全抽象成一个方法
    6         raise NotImplemented('未实现')
    7 
    8 class Word(Document): pass # 其他功能略去
    9 class Pdf(Document): pass # 其他功能略去

      基类提供的方法不应该具体实现,因为他未必适合子类的打印,子类需要覆盖重写。

      基类中只定义了,不实现的方法,称为抽象方法 在Python中,如果采用这种方式定义的抽象方法,子类可以不实现,知道子类使用该方法的是才报错。
      
      print算是一种能力,打印功能,不是所有的Document的子类都需要的,所以,从这个角度出发,有点问题。

     2、需要打印的子类上增加
      如果在现有子类上直接增加,违反了Ocp原则,所以应该继承后增加:

    
    
     1 class Document:
     2     def __init__(self, content):
     3         self.content = content
     4 
     5     def print(self):# 没有实现,完全抽象成一个方法,这个方法是知道所有的子类必须实现。
     6         raise NotImplemented('未实现')
     7 
     8 class Word(Document): pass # 其他功能略去
     9 class Pdf(Document): pass # 其他功能略去
    10 
    11 
    12 # 单继承 这就是OCP,不要在第三方库修改,继承下来,增强或修改
    13 class PrintableWord(Word):
    14     def print(self):
    15         print(self.content)
    16 
    17 
    18 print(PrintableWord.__dict__)
    19 print(PrintableWord.mro())
    20 
    21 pw = PrintableWord('test string')
    22 pw.print()
    23 
    24 # {'__module__': '__main__', 'print': <function PrintableWord.print at 0x0000000002960378>, '__doc__': None}
    25 # [<class '__main__.PrintableWord'>, <class '__main__.Word'>, <class '__main__.Document'>, <class 'object'>]
    26 # test string
      看似不错,如果需要还要提供其他的能力,如何继承?
      应用于网络,文档应该具备序列化能力,类上就应该实现序列化。
      可序列化还可能分为使用pickle,json,messagepack等

      这个时候发现,为了增加一种能力,就要增加一次继承,类可能太多了,继承的方式不是很好了。
      功能太多,A 类需要某几样功能,B类需要另几样功能,它们需要的是多个功能的自由组合,继承实现很繁琐。

      3、装饰器
      用装饰器增强一个类,把功能给类附加上去,哪个类需要,就装饰它。
     1 class Document:
     2     def __init__(self, content):
     3         self.content = content
     4 
     5     def print(self):# 没有实现,完全抽象成一个方法
     6         raise NotImplemented('未实现')
     7 
     8 class Word(Document): pass # 其他功能略去
     9 class Pdf(Document): pass # 其他功能略去
    10 
    11 
    12 def printable(cls):
    13     def _print(self):
    14         print(self.content)
    15     cls.print = _print
    16     return cls
    17 
    18 # 单继承 这就是OCP,不要在第三方库修改,继承下来,增强或修改
    19 @printable # PrintableWord = printable(PrintableWord)=PrintableWord
    20 class PrintableWord(Word):pass
    21     # def print(self):
    22     #     print(self.content)
    23 
    24 pw = PrintableWord('test string')
    25 pw.print()

        注意:上图 如果在类里边,如果实例 self在 print方法中,直接调用print的话,就会出错,递归调用,自己调用自己。

      优点:

        简单方便,在需要的地方动态的加入,直接使用装饰器,可以为类灵活的增加功能

      4、Mixin

        举例:

     1 class Document:
     2     def __init__(self, content):
     3         self.content = content
     4 
     5     def print(self):
     6         raise NotImplemented
     7 
     8 class Word(Document):pass
     9 
    10 # 简单的实现了一个Mixin 类,添加了一个打印功能
    11 class PrintTableMixin:
    12     def print(self):
    13         print('{}:{}'.format(type(self).__name__, self.content))
    14 
    15 # 再对之前的Mixin再做修饰
    16 class SuperPrintableMixin(PrintTableMixin):
    17     def print(self):
    18         print('!!!!!!!!!!!!!!!!!!!!!!!!!!!!')
    19         super().print()
    20         print('!!!!!!!!!!!!!!!!!!!!!!!!!!!!')
    21 
    22 # 继承了Mixin 类
    23 class SuperPrintableWordMixin(SuperPrintableMixin, Word):pass
    24 
    25 # 实例化一个被修饰后的实例
    26 swm = SuperPrintableWordMixin('test word')
    27 swm.print()

      打印结果:

    1 !!!!!!!!!!!!!!!!!!!!!!!!!!!!
    2 SuperPrintableWordMixin:test word
    3 !!!!!!!!!!!!!!!!!!!!!!!!!!!!
    打印结果
      Mixin就是其他类混合进来,同时带来了类的属性和方法。
      这里看来Mixin 类 和装饰器效果一样, 也没有什么特别的,但是Mixin就是类,就可以继承。!!!
      
      总结:
        Mixin本质上就是类,就是多继承实现的
        Mixin体现的是一种组合的设计模式
        在面向对象的设计中,一个复杂的类,往往需要很多的功能,而这些功能有来自不同的类提供,
        这就需要很多的类组合在一起
        从设计模式的角度来说,多组合,少继承
         
        Mixin 类的使用原则;
        • Mixin 类中不应该显示的出现__init__ 初始化方法
        • Mixin 类通常不能独立工作,因为他是准备混入别的类中的部分功能实现
        • Mixin 类的最先类也是Mixin类
        使用时:Mixin 类通常在继承列表的第一个位置,
            例如:class PrintWord(PrintMixin, Word):pass
            因为深度优先,如果放在右侧,可能会出现异常,如果其他父类也实现了该方法,但是功能不一定一样,所以导致结结果不同!

     

    练习:

     1 import math
     2 import pickle
     3 
     4 class Shape:
     5     def __init__(self):
     6         pass
     7 
     8     def area(self):
     9         raise NotImplemented('未实现')
    10 
    11 # class ser:
    12 #     def serialize(self):
    13 #         s = pickle.dumps(self.area())
    14 #         return s
    15 #
    16 # class circle(ser, Shape):
    17 #     def __init__(self, r):
    18 #         self.r = r
    19 #
    20 #     def area(self):
    21 #         area =  math.pi * (self.r ** 2)
    22 #         return  area
    23 
    24 def ser(cls):
    25     def serialize(self):
    26         s = pickle.dumps(self.area())
    27         return s
    28     cls.ser = serialize
    29     return cls
    30 
    31 
    32 @ser # cricle = ser(cricle)
    33 class circle(Shape):
    34     def __init__(self, r):
    35         self.r = r
    36 
    37     def area(self):
    38         area =  math.pi * (self.r ** 2)
    39         return  area
    40 
    41 c = circle(4)
    42 print(c.area())
    43 print(c.ser())
    44 print(circle.__dict__)
    45 
    46 
    47 
    48 
    49 class triangle(Shape):
    50     def __init__(self, a, b, c):
    51         self.a = a
    52         self.b = b
    53         self.c = c
    54     def area(self):
    55         p = (self.a + self.b + self.c) / 2
    56         q = math.sqrt(p * (p-self.a) * (p-self.b) * (p-self.c))
    57         return p / q
    58 
    59 class square(Shape):
    60     def __init__(self, a):
    61         self.a = a
    62 
    63     def area(self):
    64         return self.a * self.a
    举例

     

     

     

     

     

     

     

     

    为什么要坚持,想一想当初!
  • 相关阅读:
    HDU 1068
    hdu6447
    HDU 6438
    网络赛的个人反思总结
    Bellman-ford 模板
    Pairs Forming LCM LightOJ
    POJ
    链式前向星
    POJ 3281 Dining
    游标遍历所有数据库循环执行修改数据库的sql命令
  • 原文地址:https://www.cnblogs.com/JerryZao/p/9665563.html
Copyright © 2011-2022 走看看