python学习笔记之继承
继承
先来看一个例子,以门这个类为例子,如下:
1 | class Door: |
上边这个“Door”类实现了两个方法,一是open
,表示把门打开,另一是close
,表示把门关闭。如果想对门加把锁,门是锁着的就打不开门,锁是打开状态时才能打开门,这时我们可以重新实现这个类,如下:
1 | class LockableDoor: |
上边的LockableDoor
类实现了我们所需要的功能,它是完全舍弃了Door
类而重新实现的类,有没有方法在不舍弃Door
类的情况下实现我们所需要的功能呢?类的继承特性就可以实现,如下:
1 | class LockableDoor_1(Door): |
在分析上边代码前先来理清几点:
没有加锁的门(Door类)有以下方法:
-
打开门(open),直接把状态(status)设置为成打开状态(opening)
-
关闭门(close),直接把状态(status)设置成关闭状态(closed)
一个有锁的门(LockableDoor_1)有以下方法:
-
打开门(open),先要看下门是否被锁住了,如果没有锁住才能把状态(status)设置成打开状态(oipening),否则就提示门是被锁住的,无法打开等信息,而一个
没有上锁
的门和一个没有锁
的门对打开门这个动作都是相同的,所在这里可以用超类的的open方法 -
关闭门(close),一个没锁的门要想关闭门把状态(status)设置成关闭状态(closed),那对一个有锁的门呢?也是一样,不管门是否上锁,我们只需把门状态(status)设置成关闭状态(closed),所以对关闭门来说与
Door类
中的close
方法并没有差异 -
上锁(lock),一个有锁的门会有加不加锁这个动作
通过上边的分析可知:
在不完全舍弃Door类
的情况下实现一个有锁的门这个类,那需要在Door类
的基础上重新实现
一个open
方法,即重写open方法
,并增加一个lock
方法,而close
方法完全可以利用Door类
中的。
现在来分析一下LockableDoor_1
这个类中的代码:
-
第一行
class LockableDoor_1(Door):
表示LockableDoor_1
类继承Door
类,Door
是LockableDoor_1
的超类,也叫父类或基类 -
第二至四行是重写了构造方法,因为增加了
is_lock
实例属性,其中super(LockableDoor_1,self).__init__(number,status)
是表示用supper函数调用了超类的__init__
方法,即在LockableDoor_1
类中实例化了超类(Door) -
第六到十行是重写了open方法,其中
super(LockableDoor_1,self).open()
表示调用父类的open方法 -
针对超类的close方法不用重写,直接继承即可
继承与可见性
1 | class A: |
1 | class B(A): |
1 | b = B() |
1 | dir(b) |
['_A__private_class_method',
'_A__private_class_var',
'_A__private_instance_method',
'_A__private_instance_var',
'__class__',
'__delattr__',
'__dict__',
'__dir__',
'__doc__',
'__eq__',
'__format__',
'__ge__',
'__getattribute__',
'__gt__',
'__hash__',
'__init__',
'__le__',
'__lt__',
'__module__',
'__ne__',
'__new__',
'__reduce__',
'__reduce_ex__',
'__repr__',
'__setattr__',
'__sizeof__',
'__str__',
'__subclasshook__',
'__weakref__',
'public_class_method',
'public_class_var',
'public_instance_method',
'public_instance_var']
从dir(b)
输出的列表的最后四个元素可总结如下规则:
- 子类可继承超类的
公有方法
,包括公有类方法和公有实例方法;子类可继承超类的公有变量
,包括公有类变量和公有实例变量
可概括如下:
-
公有方法和变量(类和实例)是可继承的
-
私有方法和变量(类和实例)是不可继承的
来调用验证一下:
1 | b.public_class_method() #公有类方法可访问公有和私有的类变量 |
public class var
private class var
1 | b.public_class_var |
'public class var'
1 | b.public_instance_method() #公有的实例方法可访问公有和私有类变量,也能访问公有和私有实例变量 |
public class var
private class var
public instance var
private instance var
1 | b.public_instance_var |
'public instance var'
如果在子类中把类变量和实例变量重写后,那子类访问到的变量是自己的,还是父类的呢?做如下验证:
1 | class C(A): |
1 | c = C() |
1 | c.public_instance_method() |
child public class var
private class var
child public instance var
private instance var
1 | c.public_class_method() |
child public class var
private class var
1 | c.public_class_var |
'child public class var'
1 | c.public_instance_var |
'child public instance var'
经过上边的验证可得到如下结论:
-
父类的公有方法(类和实例)访问父类的私有变量,即使在子类中私有变量被重写了
-
子类中对公有变量重写后,父类的公有方法(类和实例)访问的是子类的公有变量