继承的作用
猫类和狗类都是动物类,但是又各有区别。如果没有继承,那么猫类和狗类就都需要创建各自的方法;如果它们都继承自动物类,那么很多共同的地方就只需要在动物类中定义一次即可,精简了代码。
继承前
继承前,各个类都需要自己定义自己的方法,代码不够精简
class Animal:
def shout(self):
print('Animal shouts')
a = Animal()
a.shout()
class Cat: #未继承Animal类,要重新定义自己的方法
def shout(self):
print('Cat shouts')
c = Cat()
c.shout()
class Dog:
def shout(self):
print('Dog shout')
d = Dog()
d.shout()
继承后
有了继承之后,子类只需要调用父类的方法就行
class Animals:
def __init__(self, name):
self._name = name
def shouts(self):
return '{} shouts'.format(self._name)
class Cat(Animals):
pass
class Dog(Animals):
pass
dog_a = Dog('wangcai')
tom_cat = Cat('tom')
print(tom_cat.shouts())
print(dog_a.shouts())
基类
所有对象的根基类都是object,可以通过以下方式来查看基类或子类
特殊属性或方法 | 含义 | 示例 |
---|---|---|
__base__ | 类的基类 | |
__bases__ | 类的基类元组 | |
__mro__ | 显示方法查找顺序,基类的元组 | |
mro()方法 | 同上,返回列表 | int.mro() |
__subclasses__() | 类的子类列表 | int.__subclasses__() |
继承中的访问控制
1.子类可以继承父类中的变量
2.子类可以直接访问父类中的公有成员和保护成员
3.保护成员的格式为_name
,以单下划线开头
4.对于私有成员__name
(以双下划线开头),子类访问时需要根据规则改变相应成员的名称。
4.改名规则为:在保护成员前面加上_A
,比如保护成员__a
,子类继承父类A,子类在访问A类中的成员时,需要将标识符的名称改为_A__a
class A:
__a = 1
_b = 2
c = 3
def __init__(self):
self.__d = 4
self._e = 5
self.f = 6
self.__a += 1
def showa(self):
print(self.__a)
print(self.__class__.__a)
def __showb(self):
print(self._b)
print(self.__a)
print(self.__class__.__a)
class B(A):
__a = 11
_b = 12
x = B() #B类没有init方法,因此会调用父类的
x.showa() #由于初始化时调用的时父类的方法,因此,再调用__a时,需要加上1
print(x._A__showb()) #私有成员需要改名访问
print(x.c)
print(x._Animal__d) #改名访问
print(x.__dict__)
print(x.__class__.__dict__.keys())
实例属性查找顺序
实例的__dict__ --> 类的__dict__ --> 如果有继承:父类的__dict__
一旦找到即返回,如果都没找到就会跑异常
方法的重写override
子类中的可以覆盖父类中的同名方法,而且也可以覆盖本类中的同名方法,因为方法名只是个标识符,可以依次覆盖
class Animals:
def __init__(self, name):
self._name = name
def shouts(self):
return 'Animals shouts'
class Cat(Animals):
def shouts(self):
return '{} shout'.format(self._name)
tom_cat = Cat('tom')
print(tom_cat.shouts()) #虽然继承自Animals类,但是子类中包含同名方法,因此会覆盖父类
方法增强super()
子类继承自父类,但父类的方法不一定完全满足子类,因此子类可以在父类方法的基础上做一些增强,相当于追加新的特性,而且不覆盖父类原有的特性。
super().method() #这样就调用了父类的方法,能够使用父类方法,并且自己的特性不会被覆盖
class Animals:
def __init__(self, name):
self._name = name
def shouts(self):
print('Animals shouts')
class Cat(Animals):
def shouts(self):
print('hahah') #子类方法的功能
super().shouts() #调用父类方法的功能
tom_cat = Cat('tommy')
tom_cat.shouts() #这样就可以执行父类和子类方法所包含的所有功能
super()方法可以访问到父类的属性,是一种静态方法和类方法,也是类属性
子类初始化方法
1.如果父类已经定义了__init__方法,再在子类中定义__init__方法的话会覆盖父类的方法,所以子类应该使用super()方法类显式调用父类的初始化方法
2.子类中显式调用父类初始化方法的位置越靠前越好
class A:
def __init__(self, a, d=10):
self.a = a
self.__d = d
class B(A):
def __init__(self, b, c):
#A.__init__(self, b + c, b - c) #调用父类初始化方法
super().__init__() #同上
self.b = b
self.c = c
def get_values(self):
print(self.b)
print(self.a)
f = B(200,300)
print(f.__dict__)
print(f.__class__.__bases__)
f.get_values()
在显式调用父类初始化方法时,推荐使用一下两种方式
super().__init__()
super(B, self).__init__()