继承
继承是面向对象一个非常重要的特性,如果没有继承那就不能称为类。
当定义一个类时,可以从现有的类继承,新的类称为子类(Sub Class)或派生类,被继承的类称为基类(Base Class),父类或超类(Super Class)。
派生类定义的语法如下:
class SubClassName(BaseClassName):
<statement-1>
...
<statement-Nm>
案例:
创建一个Animal类用来表示动物,一个Cat类用来表示猫,一个Dog类用来表示狗。
# 定义一个Animal类表示动物
class Animal:
name = '动物'
def eat(self):
print('吃东西')
def drink(self):
print('喝水')
def sleep(self):
print('睡觉')
def call(self):
print('喊叫')
# 继承
# 定义一个Cat类继承Animal类表示猫
class Cat(Animal):
pass
# 定义一个Dog类继承Animal类表示狗
class Dog(Animal):
pass
这个案例中Cat,Dag
继承了Animal
类,那么Animal
是Cat
,Dog
的父类,Cat
,Dog
是Animal
的子类。
继承的具体体现是子类会继承父类的属性和方法。
虽然在Cat
,Dog
类中没有定义任何的属性和方法,但它们自动继承了父类Animal的属性和方法。
print(dir(Cat))
输出:
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'call', 'drink', 'eat', 'name', 'sleep']
可以在属性中看到call
,drink
,eat
,sleep
,name
。
cat = Cat()
print(cat.name)
cat.eat()
cat.drink()
cat.sleep()
cat.call()
输出:
动物
吃东西
喝水
睡觉
喊叫
多继承
python支持多继承,继承多个父类的子类定义语法如下:
class SubClassName(Base1,Base2,Base3):
<statement-1>
...
<statement-Nm>
多继承最简单的情况是,父类之间是无关的,这时搜索从父类所继承的属性的操作是深度优先,从左至右的。因此如果某一属性在SubClassName
中未找到,则会在Base1
中搜索它,然后(递归地)到Base1
的父类中搜索,如果找不到,再到Base2
中搜索,依此类推。
class A:
name = 'A'
class B(A):
pass
class C(B):
pass
class D:
name = 'D'
class E(C, D):
pass
print(E.name)
输出:
A
上面的代码中类的继承关系为:
所以E.name
查找的顺序为E,C,B,A,D
。
有时候,继承关系比这个更复杂,如果D
的父类也是A
,那结果就不一样了。
class A:
name = 'A'
class B(A):
pass
class C(B):
pass
class D(A):
name = 'D'
class E(C, D):
pass
print(E.name)
输出:
D
python中多继承时类的继承顺序时通过mro
算法计算出来的,打印类的__mro__
属性,可以返回继承顺序:
print(E.__mro__)
输出:
(<class '__main__.E'>, <class '__main__.C'>, <class '__main__.B'>, <class '__main__.D'>, <class '__main__.A'>, <class 'object'>)
所以E.name
查找的顺序为E,C,B,D,A
,最后输出D
.
方法重写
父辈的东西不一定适合我们,我们可以创造属于自己的世界!嘿嘿。
父类的属性和方法也不一定完全适合子类,子类可以通过重写覆盖不合适的属性和方法。
在子类中定义父类中同名的方法和属性会覆盖父类的方法和属性,也叫重写。
案例:
在上面的案例中,虽然Cat
,Dog
类继承了Animal
的属性和方法,但是不能区别Cat
和Dog
,所以大部分方法和属性不合适,需要重写。
class Cat(Animal):
name = '猫'
def eat(self):
print('猫吃鱼')
def call(self):
print('喵喵叫')
class Dog(Animal):
name = '狗'
def eat(self):
print('狗吃骨头')
def call(self):
print('汪汪叫')
分别重写了属性name
和方法eat
和call
cat = Cat()
print(cat.name)
cat.eat()
cat.call()
输出:
猫
猫吃鱼
喵喵叫
dog = Dog()
print(dog.name)
dog.eat()
dog.call()
输出:
狗
狗吃骨头
汪汪叫