继承:
继承是一种创建新类的方式,
在python中,新建的类可以继承一个或多个父类(基类或超类),新建的类是所继承的类的(派生类或子类)
人类和狗 有相同的属性, 提取了一个__init__方法,在这个方法里放一些共有的属性
人类和狗 在相同的方法,提取了一个def func():方法,在这个方法里放一些共有的方法
单继承和多继承
class Par1: pass class Par2: pass class Sub1(Par1): pass class Sub2(Par1,Par2): pass #__base__只查看从左到右的第一个父类,而__bases__查看所有父类 print(Sub1.__bases__) #(<class ‘__main__.Par1‘>,) print(Sub2.__bases__) #(<class ‘__main__.Par1‘>, <class ‘__main__.Par2‘>) ------------------------------------ print(Par1.__base__) #<class ‘object‘>
如果没有指定基类,python的类默认继承object类,object类是所有类的基类,它提供了一些常见的方法(如__str__)的实现
class Par1: def __init__(self,name): self.name = name def __str__(self): return self.name p = Par1(‘kitty‘) print(p) # kitty
class Foo1: def __init__(self,name): # self是f对象 self.name = name def __str__(self): return self.name class Foo2(Foo1): a = 1 f = Foo2(‘kitty‘) #Foo2中没有__init__函数,就去基类去找,然后传入参数 print(f.name) # kitty
继承与抽象:
世间本来没有人类,只是很多个具体的人对象,后来把所有的人抽象成(划规成)一类,才有了人类的概念
so: 抽象是从下往上
继承从上往下
继承与重用性:
继承的目的是为了减少代码的重复性
比如:
想创建一个b类, 但是发现b类的属性大部分和a类的相同, 就让b去继承a的属性,节省代码
提示:用已经有的类建立一个新的类,这样就重用了已经有的软件中的一部分设置大部分,大大生了编程工作量,这就是常说的软件重用,不仅可以重用自己的类,也可以继承别人的,比如标准库,来定制新的数据类型,这样就是大大缩短了软件开发周期,对大型软件开发来说,意义重大.
经典类 和 新式类:
python3都是新式类 (新式类默认继承object class Foo(object): == class Foo: )
python2中经典类和新式类共存
- class Foo: 是经典类
- class Foo(object): 是新式类
钻石继承:
- 经典类: 深度优先,就是单线走到头,再去其它线
- 新式类: 就是单线走到剩余最后一个父类停止,再去找其它线,最后一条线走到尾
经典类继承顺序:
深度优先
新式类继承顺序:
广度优先:
如果找到b就去找c c再去找e e在去找f f没有就报错了 因为f找不到d 单线
=====================================================
python2 中: 最原始的加上object,往后的都会继承object
======================================
再来看:
class D: def __init__(self): print(‘d‘) class C(D): def __init__(self): print(‘c‘) super().__init__() class B(D): def __init__(self): print(‘b‘) super().__init__() class A(B,C): def __init__(self): print(‘a‘) super().__init__() #mro a = A() print(A.mro()) ##结果如下: a b c d [<class ‘__main__.A‘>, <class ‘__main__.B‘>, <class ‘__main__.C‘>, <class ‘__main__.D‘>, <class ‘object‘>] 和mro的顺序一样 广度优先 (super只有新式类中有) 在多继承中,super不只是寻找当前类的父类,而是依据mro顺序, 从A节点出发,根据广度优先排序查找下一个类
派生
派生:
class A: # 基类(提取了狗和人的共同属性) def __init__(self,name, aggressivity, life_value): #里面的self是对象 self.name = name self.aggressivity = aggressivity self.life_value = life_value def eat(self): print(‘A eating‘) class Dog(A): # 定义一个狗类 def __init__(self,name, aggressivity, life_value,breed,): #派生一个__init__方法 #A.__init__(self,name, aggressivity, life_value) : 类名.__init__(参数) super().__init__(name, aggressivity, life_value) #调用基类__init__方法:super().__init__() self.breed = breed # 每一只狗都有自己的品种; def bite(self,people): #派生bite方法 父类中没有的属性&方法 people.life_value -= self.aggressivity def eat(self): #重新定义eat (派生) A.eat(self) #如果想加上父类的方法: A.eat(对象) print(‘dog eating‘) class Person(A): # 定义一个人类 def __init__(self,name, aggressivity, life_value,money): #派生 super().__init__(name, aggressivity, life_value) #调用基类__init__方法 self.money = money def attack(self,dog): dog.life_value -= self.aggressivity def get_weapon(self,weapon_obj): if self.money > weapon_obj.price: self.money -= weapon_obj.price # 金老板花钱买武器 self.weapon = weapon_obj # 金老板装备打狗棒 self.aggressivity += weapon_obj.aggr # 金老板的攻击力增加了 jin = Person(‘jin‘,250,250,100) dog = Dog(‘酷狗‘,33,50,‘藏獒‘) print(jin.name) # jin print(jin.money) # 100 print(dog.name) # 酷狗 print(dog.breed) # 藏獒 dog.eat() # A eating # dog eating ------------------- A.eat(dog) #A eating 类名.方法名(对象名) -------------------------------- super(Dog,dog).eat() #A eating super(类名,对象名) super在外面用,必须传参数 ========================================
派生方法和属性:
1.在子类中增加父类没有的
2.如果再调用父类的的方法和属性
父类.__init__(self,参数...)
super()__init__(参数...) ? 指名道姓调用
在类外面用super的时候, super(子类名,对象).属性
小结:
子类有,用自己的,没有用父类的
子类有,父类有,仍然想用父类的:
经典类: 父类.__init__(self,参数...) 父类.方法名(对象)
新式类: super().__init__(参数...) 父类.方法名(对象)
一般情况下super都满足了
指名道姓调用父类的方法 父类.方法(self) self是子类的对象
例题:打印结果
class Foo: def __init__(self): (self是对象,对象自己有func()) self.func() def func(self): print(‘父类‘) class Son(Foo): def func(self): print(‘子类‘) s = Son() #子类 ---------------- print(Son.mro()) 新式类才有的查看继承顺序的方法: print(类名.mro()) [<class ‘__main__.Son‘>, <class ‘__main__.Foo‘>, <class ‘object‘>]