python面向对象编程(二)类的继承

继承性最根本的作用就是避免编写重复代码,在创建一个类的时候,形参中定义一个类名,表示该类是从哪个类继承而来的,如果没有合适的继承类,用object,因为所有的类最终都会继承object这个类。

class Person (object):
    pass
p = Person()

类的继承

类怎么继承呢,在ES6中类的继承是通过extend,在类的constructor方法中还要定义一个关键字super,它指向父类,执行super()才能实现真正的继承;在python中,子类继承父类需要在子类形参中定义父类的名字:

# 父类 Animal
class Animal (object):
    def run(self,param):
        print('%s is running' % param)

# 子类Dog
class Dog (Animal):
    pass

# 子类Cat
class Cat (Animal):
    pass

dog = Dog()
cat = Cat()
dog.run('dog')  # dog is running
cat.run('cat') # cat is running

上边代码,分别定义了父类Animal,子类Dog和Cat,两个子类继承了父类Animal的所有属性和方法,所以通过实例都能够访问父类的实例方法。

有几点值得注意:

1、子类和父类同时定义了相同的方法,子类方法会覆盖父类方法;

2、当定义一个类的时候,实际上定义的是一种数据类型。定义的数据类型与Python自带的数据类型如:列表list、元组tuple、字符串str、集合set、dict字典一样!

3、可以使用isinstance()来判断一个元素是否是某个类型:

# 判断li是否是一个列表
li = []
judge_type = isinstance(li,list)
print(judge_type) # True

# 判断子类dog是否是Dog
class Animal (object):
    pass
class Dog (Animal):
    pass
dog = Dog()
judge_type1 = isinstance(dog,Dog)
judge_type2 = isinstance(dog,Animal)
print(judge_type1) # True
print(judge_type2) # True

上边代码,dog的数据类型即是Dog也是Animal,因为dog是Dog创建的一个实例对象,而Dog子类是继承自Animal父类的,这样就不难理解为什么上边我们用isinstance判断输出都是True。

不同文件下子类继承父类的实例变量

如果父类在别的文件夹下,我们可以通过引入模块的形式实现子类继承父类:

# 假设father文件 是在 m 文件夹下
class Father(object):
    def __init__(self,name,age):
        self.name = name
        self.age = age

#son文件,子类son需要继承 Father父类
# from m import Father
class Son (Father):
    def fn (self):
        print(self.name) # '呆呆君'
        print(self.age) # 100
s = Son ('呆呆君',100)
s.fn()

上边代码,借用父类__init__构造函数,在子类中输出父类中定义的实例变量;子类还可以定义自己的实例变量。。。

 

不同文件下子类继承父类的方法

有两种方法:(常用的是第二种方法,下边两种方法,调用父类方法时,python都不会为实例方法的第一个参数self绑定实例对象,所以需要手动显示的绑定第一个参数self   !!!)

1、直接用过    父类.方法 调用

2、通过super( 子类,self ) .父类的方法 () 或python3中的简写:super( ).父类方法( )

# 下边的父类是在  py_package文件夹  下的  m1文件  中
class Father():
    def fn (self,name,age):
        print(name)
        print(age)
# 子类引入父类
from py_package.m1 import Father

class Son (Father):
    def __init__(self,name,age):
        # 方法一
        Father.fn(self,name,age) # '呆呆君'   100
        # 方法二
        super(Son, self).fn(name,age) # '呆呆君'   100
s = Son ('呆呆君',100)

上边代码,在子类Son构造函数中引入父类Father的fn方法,经常用到的是方法二使用super( )调用父类方法

使用super()也可以去调用父类构造函数,与调用普通方法一样。

当子类方法与父类方法重名,会执行子类的方法,父类方法不会输出:

# 父类
class Father():
    def fn(self):
        print('父类')
# 子类
from py_package.m1 import Father
class Son (Father):
    def fn(self):
        print('子类')
s = Son ()
s.fn() # '子类'

上边代码,子类继承了父类,都有fn方法,但是最后输出的是子类中的方法的结果,也叫作重写父类方法。

如果想输出父类fn的的结果,需要使用super()

from py_package.m1 import Father
# f = Father
class Son (Father):
    def fn(self):
        super(Son, self).fn()
        print('子类')
s = Son ()
s.fn()
# 父类
# 子类

上边代码,我们在子类实例方法fn中使用super调用了父类实例方法fn,结果输出了父类方法的结果。。。

 

补充:

关于super函数是否是调用了父级的方法或属性问题,先来看下简单的小例子:

类B和C 继承 A,而类D 继承 B和C,来看下打印顺序:

d 和b的顺序没问题,但是当执行类B时,按道理应该去调用类A的__init__方法,然而它调用了类C的方法了,原因:super( )方法调用的顺序规则必须符合 mro算法:

 

当D继承B和C时,它会先执行D,然后接着执行B,然后C,最后才执行A:

我们也可以打印python内置函数 __mro__也能看到其执行顺序:

 

 

 

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值