Python中类与类之间可以继承,继承的叫父类或超类,新创建的叫子类。通过继承,子类可以使用父类的属性,这样可以有效减少代码的冗余度,提高代码重用性。
谈到类的继承,首先要了解构造函数或构造方法。
在Python中,一个类,不管是否写了构造函数,它都是具有构造函数的一个类,它可以拥有多个构造函数,但建议一个类只有一个构造函数。
当一个对象被创建后,会立即调用构造函数。例如,我们创建了example类如下:
class example_a(object):
def add(self,a,b):
return a + b
test_a = example_a()
print(test_a.add(10,20)) ## 30
#####################################
class example_b(object):
def __init__(self,a,b):
self.a = a
self.b = b
def add(self):
return self.a + self.b
test_b = example_b(10,20)
print(test_b.add()) ## 30
在类example_a中,我们没有给出构造函数,因为class类是默认有构造函数的,只是没有显示出。class类默认的构造函数是不带参数的,因此在实例化的时候,test_a = example_a()不带参数。
在类example_b中,我们定义了构造函数def __init__(self,a,b) ,test_b=example_b(10,20)就是对example_b类进行实例化。
了解了构造函数后,我们再来看类的继承。
我们首先定义一个父类和2个子类。
class Father(object):
def __init__(self):
self.name = 'XiaoMing'
print ( "Name : %s" %( self.name) )
def get_name(self):
return "Name : " + self.name
class Son_A(Father):
def get_name(self):
return 'Name : '+self.name
class Son_B(Father):
def __init__(self):
self.age= 18
print ( "Age is " + str(self.age) )
def get_age(self):
return 'Age is ' + str(self.age)
这里,子类 Son_A 和 Son_B 都继承了父类,但子类 Son_A 没有重写 __init__()函数,因此在实例化子类 Son_A 时,会自动调用父类定义的 __init__()函数;而子类 Son_B 重写了__init__()函数,因此在实例化 Son_B 子类,就不会调用父类已经定义的__init__()函数。
这里,需要注意重写与C++里面的重载有区别,C++中允许在同一范围中声明几个功能类似的同名函数,函数根据形参个数、类型或顺序的不一样,调用不同的方法。但在Python中,不允许有重名的函数,如果有重名的函数,后出现的函数会将之前的函数覆盖掉,因此在python中几乎没有重载。
Son_B 子类重写了__init__()函数,但却没有任何关于父类的特性。因此,在很多情况下,我们必须要调用父类的构造方法来确保基本的初始化。我们完全可以将父类的构造函数复制到子类中去,然后对子类进行重写,但这就变得十分繁琐,失去了继承的意义。这里我们介绍三种方法对父类进行继承。
第一种
在子类的__init__()函数中,添加 父类名称.__init__(self,参数1,参数2,...),如下代码:
class Father(object):
def __init__(self):
self.name = 'XiaoMing'
print ( "Name : %s" %( self.name) )
def get_name(self):
return "Name : " + self.name
class Son_C(Father):
def __init__(self):
Father.__init__(self)
self.age= 18
print ( "Age is " + str(self.age) )
def get_age(self):
return 'Age is ' + str(self.age)
第二种
在子类的__init__()函数中,添加 super().__init__(参数1,参数2,...),代码如下:
class Father(object):
def __init__(self):
self.name = 'XiaoMing'
print ( "Name : %s" %( self.name) )
def get_name(self):
return "Name : " + self.name
class Son_C(Father):
def __init__(self):
super().__init__()
self.age= 18
print ( "Age is " + str(self.age) )
def get_age(self):
return 'Age is ' + str(self.age)
第三种
在子类的__init__()函数中,添加 super(Son_C,self).__init__(参数1,参数2,...),代码如下:
class Father(object):
def __init__(self):
self.name = 'XiaoMing'
print ( "Name : %s" %( self.name) )
def get_name(self):
return "Name : " + self.name
class Son_C(Father):
def __init__(self):
super(Son_C,self).__init__()
self.age= 18
print ( "Age is " + str(self.age) )
def get_age(self):
return 'Age is ' + str(self.age)
注意,在第一种继承方法中,如果一个父类有多个子类,子类(相当于父类)中又有多个子类,即一个子类D继承了2个父类B和C,两个父类B和C又继承了父类A,且每个类都有__init__()方法,那么如果使用第一种方法对类进行继承,可能会出现父类A被重复执行多次,因为子类D会调用父类B和C,而父类B和C又分别调用了父类A,这样父类A就会被重复执行2次,造成了资源的浪费。所以,一般建议使用super方法。
当 super 去调用父类的方法时,这里需要注意调用的顺序问题,super 调用父类的顺序,是由 python 解释器里面的C3算法决定的(多继承查找规则),具体可以通过下列代码查看:
print(Son_C.__mro__)
##输出结果##
(, , )
mro元组的先后顺序就是super调用父类时的顺序。例如,当在Son_C类中执行super时,根据mro元组顺序,super会调用
新式类与经典类的区别:
继承了object的类以及该类的子类,都是新式类。
在Python3中如果一个类没有继承任何类,则默认继承object类。因此python3中都是新式类
没有继承object的类以及该类的子类,都是经典类。
在Python2中如果一个类没有继承任何类,不会继承object类。因此,只有Python2中有经典类。