python中的继承
继承的意义在于可以复用前面一个类的方法和属性,避免了代码重复,提高开发效率,作为一个程序员简洁应该是每个程序员应该追求的,那么继承就可以帮我们很好的做到这一点
接下来我们来看一个不使用继承的例子:
class Parent:
def __init__(self, name):
self.name = name
def eat(self, foot):
return '{} is eating {}'.format(self.name, foot)
class Children:
def __init__(self, name):
self.name = name
def eat(self, foot):
return '{} is eating {}'.format(self.name, foot)
c = Children('Amy')
print(c.name) # Amy
print(c.eat('rice')) # Amy is eating rice
p = Parent('Amy')
print(p.name) # Amy
print(p.eat('rice')) # Amy is eating rice
看完这个例子肯定有人要问,这两个类的内容不是一毛一样的吗,这样写着多麻烦啊,如果还有几个一样的方法是不是还要加几个一样的,所以说当然不喽,接下来继承就派上用场了
单继承
class Parent:
def __init__(self, name):
self.name = name
def eat(self, foot):
return '{} is eating {}'.format(self.name, foot)
class Children(Parent):
pass
c = Children('Amy')
print(c.name) # Amy
print(c.eat('rice')) # Amy is eating rice
p = Parent('Amy')
print(p.name) # Amy
print(p.eat('rice')) # Amy is eating rice
从上面的例子发现当使用继承后class Children(Parent)
,那么好像被继承类的属性和方法都被继承类使用了,其实也确实如此
多继承
class Animal:
def __init__(self, name):
self.name = name
def eat(self, foot):
return '{} is eating {}'.format(self.name, foot)
class Fish:
def eat(self, foot):
return 'This is {}'.format(foot)
class Shark(Fish, Animal):
pass
s = Shark('kitty')
print(s.name) # kitty
print(s.eat('rice')) # This is rice
注意看一下,我们的Shark类继承了两个类,Animal类定义了name属性,但是Fish类并没有定义name属性,再看一下执行结果,我们发现,s.name执行结果是kitty,也就是说继承了Animal类,但是s.eat(rice)却执行了This is rice,也就是说它只继承了Fish类,所以结论是:当处于多继承时采用就近原则,如果就近没有再执行后面的,这是通俗理解,其实本质是调用了以下的方法,并按打印结果由左至右顺序执行,如果找到最后一个类,还没有找到方法,程序报错
print(Shark.__mro__)
# (<class '__main__.Shark'>, <class '__main__.Fish'>, <class '__main__.Animal'>, <class 'object'>)
但是问题又来了,上面的继承我们完全继承了,那我们想要继承但是又想要自己定义该怎么办呢,别急,下面就给介绍方法重写
方法重写
class Animal:
def __init__(self, name):
self.name = name
def eat(self, foot):
return '{} is eating {}'.format(self.name, foot)
class Fish(Animal):
def __init__(self, name, age):
Animal.__init__(self, name) # self参数一定要加上
self.age = age
f = Fish('Amy', 18)
print(f.name) # Amy
print(f.age) # 18
上面这种方法是使用类去继承父类,但是它是有弊端的,比如说如果父类变了,那么继承父类的方法都要修改,但是他的弊端还不仅如此,比如:
class Animal:
def __init__(self, name):
self.name = name
class Fish:
def __init__(self, age):
self.age = age
class Shark(Animal, Fish):
def __init__(self, name, age):
Animal.__init__(self, name)
Fish.__init__(self, age)
s = Shark('kitty', 18)
print(s.name) # kitty
print(s.age) # 18
从上面的代码发现问题又来了,如果是多继承呢,那么方法就需要写多个继承,那么再继承多点,岂不是还要多写几个,答案是的,但是有没有方法改善呢,答案还是有的,我们可以调用super()函数
class Animal:
def __init__(self, name, *args):
super().__init__(*args)
self.name = name
class Fish:
def __init__(self, age, *args):
super().__init__()
self.age = age
class Shark(Animal, Fish):
def __init__(self, name, age):
super().__init__(name, age)
s = Shark('kitty', 18)
print(s.name) # kitty
print(s.age) # 18
print(Shark.__mro__)
# (<class '__main__.Shark'>, <class '__main__.Animal'>, <class '__main__.Fish'>, <class '__main__.Biology'>, <class 'object'>)
super()调用过程:上面s初始化时,先执行Shark中__init__
方法,其中的__init__
有super()调用,每执行一次super()时,都会从__mro__
方法元组中顺序查找搜索。所以先调用Fish的__init__
方法,在Fish中又有super()调用,这个时候就就根据__mro__
表去调用object中的__init__
,然后调用Animal的__init__
,在Animal中又有super()调用,这个就根据__mro__
表又去调用object中的__init__
.
优先级
class A:
def f1(self):
print("A")
self.f2()
class B(A):
def f2(self):
print("B")
class C:
def f2(self):
print("C")
class D(C,B):
pass
d1 = D() # self指向d1
d1.f1() # A,C
以上执行流程:D无找C,C无找B,B无找A,A有。A中调用f2()方法,同样从D开始,D无找C,C有结束,所以打印A C