Inheritance

OOP三要素之一,继承

    • 人类和猫都继承自动物类。

    • 个体继承自父母,集成了父母的一部分特征。

    • 在面向对象的世界中,从父类继承,就可以直接拥有弗雷德属性和方法,这样可以减少代码,多复用。子类可以定义自己的属性和方法。

  • 类的继承

    • 对于python来讲,所有的祖先都是object,所有的类都继承自objec

class Animal:

   def __init__(self, name):

       self._name = name

   @property

   def name(self):

       return self._name

   def shout(self):

       print('Animal shout')

class Cat(Animal):# 子类继承父类

   def shout(self):

       print('miao') # override

class Persian(Cat): #看一下__dict就知道继承了什么属性

   def __init__(self):

       self.eyes = 'blue'

class Dog(Animal):

   def run(self):

       print('Dog run')

tom = Cat('tom')

print(tom.name)

print(tom.__dict__)

dog = Dog('ahuan')

print(dog.name)

dog.shout()

ani = Animal('monster')

ani.shout()

cat = Cat('garfield')

cat.shout()

print(cat.name)

tom

{'_name': 'tom'}

ahuan

Animal shout

Animal shout

miao

garfield

  • 增加了代码的复用,减少了冗余。

  • 有自己的特点,先继承,再覆盖

  • 从上面的例子看出,通过继承,子类不用写代码,直接继承了父类的属性和方法。

Inheritance

  • Superclass父类,fatherclass ,基类

  • childclass  ,派生类

  • object类,python2.2之后引入的,它是所有类的共同祖先类。

    • Python2 中为了兼容,分为古典类class A(object):和新式类class A():。

  • python3之后都是是新式类

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

  • 父类的就是你的,传什么就是什么,如self。

  • 实例继承的属性,放在实例类的实例上,即实例的一定放在实例上。只是self.的。类的放在类属性上。

  • 私有的都是不可访问的

多继承

  • OCP(Open-Closed Principle)原则:

  • Software entities should be open for extention,but closed for modification.

    • 多继承、少修改

    • 继承的用途:增强基类、实现多态

  • 多态:

    • 在OOP中,superclass和childclass是通过继承联系在一起,如果通过一套方法,实现不同表现就是多态。

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

  • 多继承的弊端及引入MRO

    • 带来路径选择问题,究竟继承哪个superclass的feature

  • MRO(method resolution order)

    • Python 使用MRO解决基类搜索顺序问题。

    • 解决base class 搜索顺序

      • MRO三种resolution order

Inheritance Of Python 类的继承_Python

  • classic,从左到右,深度优先策略。2.2之前是MyClass,D,B,A,C,A

  • 新式类,重复的只保留最后一个。MyClass,D,B,C,A,object

  • C3算法,在类被创建出来的时候,就计算出一个MRO有序列表。.MRO,返回一个有序列表。解决了多继承的二义性。

    • lst = MyClass,D,B,C,A,object

  • 多继承的缺点

类很多,继承复杂,继承路径太多,很难说清什么样的继承路径,语法允许多继承,但解释执行时执行时候才发现错误。

团队协作开发,如果引入多继承,代码不可控。

不论是否支持多继承,都应当避免多继承。

Python的面向对象,太灵活,太开放,注重规矩。

增加需求

  • 不完整的一个类,需要一个临时使用的方法,用上多继承的方法,组合在这个类中。

  • 新建一个需要的子类,可以增加和覆盖原有不便的方法,这时候实例是子类的实例。

需求:

为Document子类提供打印能力

思路:

1、在Document中提供print方法

基类提供的方法不应该具体实现,子类需要覆盖重写。print算是一种能力,不是所有的Document子类都需要。

2、需要打印的子类上增加

继承后增加,不用在子类上直接增加,遵循了OCP原则。但是如果遇到需要不确定的多项功能时,需要增加的子类过多。

3、装饰器

  • printable相当于把PrintableWord的名字,即这个标示符拿去,就是拿了这个类(函数)对象,作为参数放到printable函数里。给它添加了一个print方法(类对象是可以动态增加类属性的)(数据的叫属性,非数据的叫方法),类对象的__dict,类本身没有变化。

  • 运行时类对象与print函数绑定,将类对象作为第一参数传入。

class Printable:

   def _print(self):

       print(self.content)

class Document:

   def __init__(self, content):

       self.content = content

class Word(Document): pass

class Pdf(Document): pass

def printable(cls):

   cls.print = lambda self: print(self.content)

   return cls

@printable  # PrintableWord=printable(PrintableWrod)

class PrintableWord(Wrod): pass

在需要的地方动态增加,直接使用装饰器,不需要对类进行修改。

4、Mixin

原则:Mixin应当覆盖或替换类的功能,在继承列表的最左边。

class PrintableMxixin:

   def print(self):

       print('--------------------------')

       print('{}'.format(self.content))

       print('--------------------------')

class Document:

   def __init__(self, content):

       self.content = content

   def print(self):

       print(self.content)

class Word(Document): pass

class PrintableWord(Word):pass

class Pdf(Document): pass

class PrintablePdf(PrintableMxixin, Pdf): 如果将Mixin放在右边则改变了mro,使用Document的print方法。

   pass

print(PrintablePdf.mro())

pdf = PrintablePdf('teset\nabc')

print(pdf.__dict__)

pdf.print()

[<class '__main__.PrintablePdf'>, <class '__main__.PrintableMxixin'>, <class '__main__.Pdf'>, <class '__main__.Document'>, <class 'object'>]

{'content': 'teset\nabc'}

--------------------------

teset

abc

--------------------------

Mixin就是其他类混合进来,同时带来了类的属性和方法。

Mixin是类,可以继承。

Mixin类的使用原则

  • Mixin类中不应该显示的出现__init__初始化方法

  • Mixin类通常不能独立工作,因为它是准备混入别的类中的部分功能实现

  • Mixin类的祖先类也应该是Mixin类