语法格式:
class 子类类名(父类1[,父类2,...]):
类体
如果在类定义中没有指定父类,则默认父类是 object类 。也就是说,object 是所有类的父类,里面定义了一些所有类共有的默认实现,比如: new()
关于构造函数:
1.子类不重写 init ,实例化子类时,会自动调用父类定义的 init
2.子类重写了 init 时,实例化子类,就不会调用父类已经定义的__init__
3.如果重写了 init 时,要使用父类的构造方法,可以使用 super 关键字,也可以使用如下格式:父类名.init(self, 参数列表)调用
class Person:
def __init__(self,name,age):
print("Person的构造方法")
self.name = name
self.age = age
def say_age(self):
print(self.name,"的年龄是:",self.age)
class Student(Person):
def __init__(self,name,age,score):
# 子类并不会自动调用父类的__init__(),我们必须显式的调用它。
# Person.__init__(self, name, age)
#super(Student,self).__init__(name,age)
print("Student的构造方法")
# self.name = name
# self.age = age
self.score = score
s1 = Student("张三",15,85)
#s1.say_age()
print(dir(s1))
1.类成员的继承和重写
1.成员继承:子类继承了父类除构造方法之外的所有成员。(私有属性、私有方法也被继承)
2.方法重写:子类可以重新定义父类中的方法,这样就会覆盖父类的方法,也称为“重写”
class Person:
def __init__(self,name,age):
self.name = name
self.age = age
def say_age(self):
print(self.name,"的年龄是:",self.age)
def say_name(self):
print("我是",self.name)
class Student(Person):
def __init__(self,name,age,score):
Person.__init__(self,name,age)
self.score = score
def say_score(self):
print(self.name,"的分数是:",self.score)
def say_name(self): #重写父类的方法
print("报告老师,我是",self.name)
s1 = Student("张三",15,85)
s1.say_score()
s1.say_name()
s1.say_age()
#执行结果
#张三 的分数是: 85
#报告老师,我是 张三
#张三 的年龄是: 15
查看类的继承层次结构:
通过类的方法 mro() 或者类的属性 mro 可以输出这个类的继承层次
结构。
class A:pass
class B(A):pass
class C(B):pass
print(C.mro())
#执行结果:[<class '__main__.C'>, <class '__main__.B'>,<class '__main__.A'>, <class 'object'>]
2.object根类
object 类是所有类的父类,因此所有的类都有 object 类的属性和方法。
深入研究一下 object 类的结构:
dir() 查看对象属性:
查看对象所有属性以及和 object 进行比对
class Person:
def __init__(self,name,age):
self.name = name
self.age = age
def say_age(self):
print(self.name,"的年龄是:",self.age)
obj = object()
print(dir(obj))
s2 = Person("高淇",18)
print(dir(s2))
运行结果:
对比发现:
1.Person 对象增加了六个属性:
dict、 module、 weakref 、age、name、say_age
2.object 的所有属性, Person 类作为 object 的子类,显然包含了所有的
属性
3.我们打印 age 、 name 、 say_age ,发现 say_age 虽然是方法,实际上也是属性。只不过,这个属性的类型是 method 而已
3.重写 str() 方法
1.object 有一个 str() 方法,用于返回一个对于“对象的描述”。内置函数 str(对象) ,调用的就是__str__()
2.str() 经常用于 print() 方法,帮助我们查看对象的信息。 str() 可以重写
class Person:
def __init__(self,name,age):
self.name = name
self.__age = age
def __str__(self):
'''将对象转化成一个字符串,一般用于print方法'''
print("重写__str__方法")
return "名字是:{0},年龄{1}".format(self.name,self.__age)
p = Person("高淇",18)
print(p)
s = str(p)
#执行结果:
#重写__str__方法
#名字是:高淇,年龄18
#重写__str__方法
4.多继承
Python支持多重继承,一个子类可以有多个“直接父类”。这样,就具备了“多个父类”的特点
5.MRO方法解析顺序
Python支持多继承,如果父类中有相同名字的方法,在子类没有指定父类名时,解释器将“从左向右”按顺序搜索
MRO(Method Resolution Order):方法解析顺序。 我们可以通
过 mro() 方法获得“类的层次结构”,方法解析顺序也是按照这个“类的
层次结构”寻找的。
用以下代码理解:
class A:
def aa(self):
print("aa")
def say(self):
print("say AAA!")
class B:
def bb(self):
print("bb")
def say(self):
print("say BBB!")
class C(B,A):
def cc(self):
print("cc")
c = C()
print(C.mro()) #打印类的层次结构
c.say() #解释器寻找方法是“从左到右”的方式寻找,此时会执行B类中的say()
#执行结果:
#[<class 'main.C'>, <class 'main.B'>, <class 'main.A'>, <class'object'>]
#say BBB!
6.菱形继承
什么是菱形继承?
B、C类继承A类,然后D类继承B、C类,这就是菱形继承
问题:
菱形继承(也称为钻石继承)可能导致二义性问题,即子类从两个父类继承了相同的方法或属性,从而不清楚在调用这个方法或访问这个属性时应该使用哪一个父类的版本。
解决:
Python通过一种称为方法解析顺序(Method Resolution Order,简称MRO)的机制来解决这个问题。
MRO定义了当子类调用一个方法时,Python将按照什么顺序在父类中查找该方法。Python 3.x 使用C3线性化算法来确定MRO,该算法确保了结果的一致性和可预测性。
C3线性化算法基于以下原则:
1.子类会先于父类被检查。
2.如果有多个父类,那么会按照它们在子类定义中出现的顺序被检查。
3.如果在继承层次结构中有多个路径导致相同的父类被检查,那么较短的路径(即包含较少中间类的路径)会被优先检查。
这种算法确保了子类中的方法会首先被考虑,然后是按照特定顺序的父类方法。如果存在冲突(即多个父类提供了相同的方法),则按照MRO的顺序来解决冲突,即首先找到的父类方法会被使用
看示例:
class A:
def method(self):
return 'A'
class B(A):
pass
class C(A):
def method(self):
return 'C'
class D(B, C):
pass
d = D()
print(d.method()) # 输出:C
在这个例子中,D 类通过 B 和 C 继承了 A 类。B 和 C 都继承了 A 的 method 方法,但 C 重写了这个方法。由于 D 在定义时首先列出了 B,然后是 C,根据C3线性化算法,D 的MRO将是 D, B, C, A, object。因此,当调用 d.method() 时,Python会首先查找 D 类中是否有 method 方法(这里没有),然后查找 B 类(这里也没有重写),接着查找 C 类(这里找到了重写的方法),所以最终输出的是 ‘C’。
通过这种方法,Python能够解决菱形继承中的二义性问题,并确保子类调用方法时的一致性和可预测性
7.super()获得父类定义
在子类中,如果想要获得父类的方法时,我们可以通过 super() 来做。super() 代表父类的定义,不是父类对象
语法:super(子类名称,self).init(参数列表)
class A:
def __init__(self):
print("A的构造方法")
def say(self):
print("A: ",self)
print("say AAA")
class B(A):
def __init__(self):
super(B,self).__init__() #调用父类的构造方法
print("B的构造方法")
def say(self):
#A.say(self) 调用父类的say方法
super().say() #通过super()调用父类的方法
print("say BBB")
b = B()
b.say()
#执行结果:
#A: <__main__.B object at 0x007A5690>
#say AAA
#say BBB