类与实例,类与子类
前言
通过这篇笔记,来达成两个目的:
一、帮助自己巩固一下python中和类有关的一些基础知识点,明晰在定义类的过程中各部分代码(主要是魔法方法)所起的作用。
二、了解类的继承到底是继承了什么?super()函数起了什么作用?调用父类方法时python的执行顺序是什么?——以此加深自己对继承的理解。
阅读正文前应掌握的两个工具
魔法属性__dict__
类名._dict_,返回一个字典,由类中所有属性、方法的键值对组成。
实例的__dict__仅存储与该实例相关的实例属性,并不包含该实例的所有有效属性。类的__dict__存储所有实例共享的变量和函数(类属性,方法等),类的__dict__并不包含其父类的属性。
class A():
z = 100
def __init__(self, a, b):
self.a = a
self.b = b
def foo(self):
print('hello')
a = A(4, 6)
print(a.__dict__) #{'a': 4, 'b': 6}
print(A.__dict__)
# {'__module__': '__main__', 'z': 100,
'__init__': <function A.__init__ at 0x000002127989ED30>,
'foo': <function A.foo at 0x000002127989EDC0>,
'__dict__': <attribute '__dict__' of 'A' objects>,
'__weakref__': <attribute '__weakref__' of 'A' objects>, '__doc__': None}
super()函数
格式:super(cls,self).方法名(参数)
cls是类名,self代指当前类的实例。(你在为哪个类写方法,这个类就是“当前类”)
python3之后,super().方法名(参数)等同于super(当前类,self).方法名(参数)。(见下方示例)
代码运行解析:类super实例化。这一实例包含了两个信息:一是以当前类为基础的MRO列表,二是处于该MRO列表中的类cls。还有一个条件:当前类必须是cls的子类。(当前类也是自身的子类,所以cls可以是当前类)
【当前类的MRO列表可以通过“print(当前类.mro())”查看】
作用:搜索在类A的MRO列表中处于类cls右方的类,找到某一方法然后调用它。例如[A,B,C,D,cls,E,F,G,object],从类E、类F、类G、类object中搜索。
class A():
def __init__(self, a, b):
self.a = a
self.b = b
print('this is A')
class B(A):
def __init__(self, a, b, c):
super().__init__(a, b) #等同于super(B,self).__init__(a,b)
#在这里可以使用“A.__init__(a,b)”代替上行代码
self.c = c
print('this is B')
B(1, 2, 3)
#this is A
#this is B
这里有个问题:虽然python3之后将super(当前类,self).方法名(参数)省略为super().方法名(参数),但并未强制我们将super()的第一个参数写成当前类的标识符。
class A():
def __init__(self):
print('this is A')
class B():
def __init__(self):
print('this is B')
class C(B, A):
def __init__(self):
super().__init__() #等同于super(C,self)
C() #将类C实例化。或者c=C()也是一样的。目的是触发类C的__init__()
#this is B
——类C的MRO列表为“[<class ‘main.C’>, <class ‘main.B’>, <class ‘main.A’>, <class ‘object’>]”。
显然,这里super()函数会调用类B的__init__方法。
但是,类C同样是类B和类A的子类。
我们可以将代码改成super(B,self)._init_() 或者super(A,self)._init_(a,b),然后创建类C的实例,因为这会触发类C的__init__方法。让我们看看会发生什么?
class A():
def __init__(self):
print('this is A')
class B():
def __init__(self):
print('this is B')
class C(B, A):
def __init__(self):
super(B,self).__init__()
C()
#this is A
class A():
def __init__(self):
print('this is A')
class B():
def __init__(self):
print('this is B')
class C(B, A):
def __init__(self):
super(A, self).__init__()
C() #
还记得类C的MRO列表吗?
[<class ‘main.C’>, <class ‘main.B’>, <class ‘main.A’>, <class ‘object’>]
当我们使用super()._init_()时,实际上是运行了代码“super(C,self)._init_()”,它会调用类B的_init_(),打印出‘this is B’;
当我们使用super(B,self)._init_()时,