python类的派生_Python3 面向对象-类的继承与派生

1、什么是继承?

继承是一种创建新类的方式,新建的类可以继承一个或多个父类(python支持多继承),父类可称为基类或超类,新建的类称为派生类和或子类。

子类会遗传父类的属性,从而解决代码重用问题。

python中类的继承分为:单继承和多继承。

class ParentClass1:

pass

class ParentClass2:

pass

class SubClass1(ParentClass1): # 单继承,基类是 ParentClass1,派生类是SubClass1

pass

class SubClass2(ParentClass1, ParentClass2): # 多继承,用逗号分隔开多个继承的类。

pass

查看继承:

print(SubClass1.__bases__) # (,)

print(SubClass2.__bases__) # (, )

经典类与新式类

1.只有在python2中才分新式类和经典类,python3中统一都是新式类

2.在python2中,没有显式的继承object类的类,以及该类的子类,都是经典类

3.在python2中,显式地声明继承object的类,以及该类的子类,都是新式类

3.在python3中,无论是否继承object,都默认继承object,即python3中所有类均为新式类

如果没有指定基类,python的类会默认继承object类,object是所有python类的基类,它提供了一些常见方法(如__str__)的实现。

print(ParentClass1.__bases__) # (,)

print(ParentClass2.__bases__) # (,)

2、继承与抽象

继承描述的是子类与父类之间的关系,是一种什么是什么的关系,必须先继承再抽象。

抽象即抽取比较像的部分。

抽象分成两个层次:

1)路人甲和路人乙这俩人比较像的部分抽取成类。

2)将人,猪,狗这三类比较像的部分抽取成父类。

抽象最主要的作用是划分类别(可以隔离关注点,降低复杂度)

继承是基于抽象的结果,通过编程语言去实现它,肯定是先经历抽象这个过程,才能通过继承的方式去表达出抽象的结构。

抽象只是分析和设计的过程中,一个动作或者说一种技巧。通过抽象可以得到类。

3、继承与重用性

==========================第一部分

例如

猫可以:喵喵叫、吃、喝、拉、撒

狗可以:汪汪叫、吃、喝、拉、撒

如果我们要分别为猫和狗创建一个类,那么就需要为 猫 和 狗 实现他们所有的功能,伪代码如下:

#猫和狗有大量相同的内容

class 猫:

def 喵喵叫(self):

print '喵喵叫'

def 吃(self):

# do something

def 喝(self):

# do something

def 拉(self):

# do something

def 撒(self):

# do something

class 狗:

def 汪汪叫(self):

print '喵喵叫'

def 吃(self):

# do something

def 喝(self):

# do something

def 拉(self):

# do something

def 撒(self):

# do something

==========================第二部分

上述代码不难看出,吃、喝、拉、撒是猫和狗都具有的功能,而我们却分别的猫和狗的类中编写了两次。如果使用 继承 的思想,如下实现:

动物:吃、喝、拉、撒

猫:喵喵叫(猫继承动物的功能)

狗:汪汪叫(狗继承动物的功能)

伪代码如下:

class 动物:

def 吃(self):

# do something

def 喝(self):

# do something

def 拉(self):

# do something

def 撒(self):

# do something

# 在类后面括号中写入另外一个类名,表示当前类继承另外一个类

class 猫(动物):

def 喵喵叫(self):

print '喵喵叫'

# 在类后面括号中写入另外一个类名,表示当前类继承另外一个类

class 狗(动物):

def 汪汪叫(self):

print '喵喵叫'

==========================第三部分

#继承的代码

class Animal:

def eat(self):

print('%s 吃' % self.name)

def drink(self):

在开发程序的过程中,如果我们定义了一个类A,然后又想新建立另外一个类B,但是类B的大部分内容与类A的相同时

我们不可能从头开始写一个类B,这就用到了类的继承的概念。

通过继承的方式新建类B,让B继承A,B会‘遗传’A的所有属性(数据属性和函数属性),实现代码重用

class Hero:

def __init__(self,nickname,aggressivity,life_value):

self.nickname=nickname

self.aggressivity=aggressivity

self.life_value=life_value

def move_forward(self):

print('%s move forward' %self.nickname)

def move_backward(self):

print('%s move backward' %self.nickname)

def move_left(self):

print('%s move forward' %self.nickname)

def move_right(self):

print('%s move forward' %self.nickname)

def attack(self,enemy):

enemy.life_value-=self.aggressivity

class ChengYaojin(Hero):

pass

class HouYi(Hero):

pass

g1=ChengYaojin('程咬金',100,300)

r1=HouYi('后裔',57,200)

print(g1.life_value) # 300

r1.attack(g1)

print(g1.life_value) # 243

用已经有的类建立一个新的类,这样就重用了已经有的软件中的一部分设置大部分,节省了编程工作量,这就是常说的软件重用,不仅可以重用自己的类,也可以继承别人的,比如标准库,来定制新的数据类型,这样就是大大缩短了软件开发周期,对大型软件开发来说,意义重大.

class Foo:

def f1(self):

print('Foo.f1')

def f2(self):

print('Foo.f2')

self.f1()

class Bar(Foo):

def f1(self):

print('Foo.f3')

b=Bar()

b.f2()

# Foo.f2 Foo.f3

# 先从自己的方法里面找

4、派生

子类也可以添加自己的新属性,或者在自己这里重新定义这些属性(不会影响到父类),需要注意的是,一旦重新定义了自己的属性与父类重名,那么调用该属性,以自己的为准。

class Hero:

def __init__(self,nickname,aggressivity,life_value):

self.nickname=nickname

self.aggressivity=aggressivity

self.life_value=life_value

def move_forward(self):

print('%s move forward' %self.nickname)

def move_backward(self):

print('%s move backward' %self.nickname)

def move_left(self):

print('%s move forward' %self.nickname)

def move_right(self):

print('%s move forward' %self.nickname)

def attack(self,enemy):

enemy.life_value-=self.aggressivity

class ChengYaojin(Hero):

pass

class HouYi(Hero):

camp='Noxus'

def attack(self,enemy): #在自己这里定义新的attack,不再使用父类的attack,且不会影响父类

print('from HouYi')

enemy.life_value += self.aggressivity

def fly(self): #在自己这里定义新的

print('%s is flying' %self.nickname)

g1=ChengYaojin('程咬金',100,300)

r1=HouYi('后裔',57,200)

print(g1.life_value)

r1.attack(g1) # 父类是减生命值,后裔的类中有attack函数,调用自己的attack函数,(300 + 57)

print(g1.life_value)

print(r1.life_value)

g1.attack(r1) # 父类是减生命值,程咬金的类没有attack函数,调用父类的attack函数,(200 - 100)

print(r1.life_value)

在子类中,新建的重名的函数属性,在编辑函数内功能的时候,有可能需要重用父类中重名的那个函数功能,应该是用调用普通函数的方式,即类名.func(),此时就与调用普通函数无异了,因此即便是self参数也要为之传值。

class Hero:

def __init__(self,nickname,aggressivity,life_value):

self.nickname=nickname

self.aggressivity=aggressivity

self.life_value=life_value

def move_forward(self):

print('%s move forward' %self.nickname)

def move_backward(self):

print('%s move backward' %self.nickname)

def move_left(self):

print('%s move forward' %self.nickname)

def move_right(self):

print('%s move forward' %self.nickname)

def attack(self,enemy):

enemy.life_value-=self.aggressivity

class ChengYaojin(Hero):

pass

class HouYi(Hero):

camp='Noxus'

def __init__(self,nickname,aggressivity,life_value):

self.nickname = nickname

self.aggressivity = aggressivity

self.life_value = life_value

def attack(self,enemy): #在自己这里定义新的attack,不再使用父类的attack,且不会影响父类

print('from HouYi')

enemy.life_value += self.aggressivity

def fly(self): #在自己这里定义新的

print('%s is flying' %self.nickname)

H1 = HouYi('xiaohong', 50, 400)

print(H1.__dict__)

#################改写:

class Hero:

def __init__(self,nickname,aggressivity,life_value):

self.nickname=nickname

self.aggressivity=aggressivity

self.life_value=life_value

def move_forward(self):

print('%s move forward' %self.nickname)

def move_backward(self):

print('%s move backward' %self.nickname)

def move_left(self):

print('%s move forward' %self.nickname)

def move_right(self):

print('%s move forward' %self.nickname)

def attack(self,enemy):

enemy.life_value-=self.aggressivity

class ChengYaojin(Hero):

pass

class HouYi(Hero):

camp='Noxus'

def __init__(self,nickname,aggressivity,life_value,skin):

Hero.__init__(self,nickname,aggressivity,life_value)

self.skin = skin #新增属性

def attack(self,enemy): #在自己这里定义新的attack,不再使用父类的attack,且不会影响父类

Hero.attack(self,enemy) #调用功能

print('from HouYi')

def fly(self): #在自己这里定义新的

print('%s is flying' %self.nickname)

H1 = HouYi('后裔', 50, 400, 'yellow')

C1 = ChengYaojin('程咬金', 30, 500)

print(H1.skin)

print(C1.life_value)

H1.attack(C1)

print(C1.life_value)

5、组合与重用性

软件重用的重要方式除了继承之外还有另外一个方式:组合

软件组合指的是,在一个类中以另外一个类的对象作为数据属性,称为类的组合。

class Equip:

def fire(self):

print('release Fire skill')

class HouYi:

camp='蓝方'

def __init__(self, nickname):

self.nickname = nickname

self.equip = Equip()

R1 = HouYi('后裔')

R1.equip.fire() # release Fire skill

组合与继承都是有效的利用已有的类资源的重要方式,但二者的概念和使用场景皆不同。

1、继承的方式

通过继承建立了派生类与基类直接的关系,它是一种‘是’的关系,比如黑猫是猫,人是动物。

当类之间有很多相同的功能,提取这些共同的功能做成基类,用继承比较好,比如老师是人,学生是人,

2、组合的方式

用组合的方式建立了类与组合的类之间的关系,它是一种‘有’的关系,比如老师有生日,老师教mysql,老师有学生等。

class People:

def __init__(self, name, age, sex):

self.name = name

self.age = age

self.sex = sex

class Course:

def __init__(self, name, price, period):

self.name = name

self.price = price

self.period = period

def show_info(self):

print('' % (self.name, self.price, self.period))

class Teacher(People):

def __init__(self, name, age, sex, job_title):

People.__init__(self, name, age, sex)

self.job_title = job_title

self.course=[]

self.students=[]

class Student(People):

def __init__(self, name, age, sex):

People.__init__(self, name, age, sex)

self.course = []

T1 = Teacher('Mr Yu', 36, '男', '首席头牌')

S1 = Student('小明', 14, '男')

python=Course('python','2500', 12)

linux=Course('linux','2000',10)

#为老师T1和学生S1添加课程

T1.course.append(python)

T1.course.append(linux)

S1.course.append(linux)

#为老师T1i添加学生S1

T1.students.append(S1)

for obj in T1.course:

obj.show_info()

当类之间有显著不同,并且较小的类是较大类所需要的组件时,用组合比较好。

6、抽象类

1)什么是抽象类

与java一样,python也有抽象类的概念,但是同样需要借助模块实现,抽象类是一个特殊的类,它的特殊之处在于只能被继承,不能被实例化。

2)为什么要有抽象类

如果说类是从一堆对象中抽取出来的,那么抽象类就是从一堆类中抽取相同的内容而来的。内容包括数据属性和函数属性。

从设计角度来看,如果类是从现实对象抽象而来的,那么抽象类就是基于类抽象而来的。

从现实角度来看,抽象类与普通类的不同之处在于,抽象类只能有抽象的方法(没有实现功能),该类不能被实例化,只能被继承,且子类必须实现抽象方法。这一点与接口有点类似,但其实是不同的。

3)在python中实现抽象类。

#_*_coding:utf-8_*_

#一切皆文件

import abc # 利用abc模块实现抽象类

class All_File(metaclass=abc.ABCMeta):

all_type = 'file'

@abc.abstractmethod # 定义抽象方法,无需实现功能

def read(self):

'子类必须定义读功能'

pass

@abc.abstractmethod #定义抽象方法,无需实现功能

def write(self):

'子类必须定义写功能'

pass

# class Txt(All_File): #子类继承抽象类,但是必须定义read和write方法

# pass # 子类没有定义抽象类方法,所以报错

# t1 = Txt() #TypeError: Can't instantiate abstract class Txt with abstract methods read, write

class Txt(All_File): #子类继承抽象类,但是必须定义read和write方法

def read(self):

print('文本数据的读取方法')

def write(self):

print('文本数据的写入方法')

t1 = Txt()

t1.read() #文本数据的读取方法

t1.write() #文本数据的写入方法

4)抽象类与接口

抽象类本质上还是类,指的是一组类的相似性,包括数据属性,函数属性。而接口只强调函数属性的相似性。

抽象类是一个介于类和接口直接的一个概念,同时具备类和接口的部分特性,可以用来实现归一化设计。

7、继承实现的原理

继承原理(python如何实现的继承)

python到底是如何实现继承的,对于你定义的每一个类,python会计算出一个方法解析顺序(MRO)列表,这个MRO列表就是一个简单的所有基类的线性顺序列表,例如

>>> F.mro() #等同于F.__mro__

[, , , , , , ]

为了实现继承,python会在MRO列表上从左到右开始查找基类,直到找到第一个匹配这个属性的类为止。

而这个MRO列表的构造是通过一个C3线性化算法来实现的。我们不去深究这个算法的数学原理,它实际上就是合并所有父类的MRO列表并遵循如下三条准则:

1.子类会先于父类被检查

2.多个父类会根据它们在列表中的顺序被检查

3.如果对下一个类存在两个合法的选择,选择第一个父类

# 继承顺序

class A(object):

def test(self):

print('from A')

class B(A):

def test(self):

print('from B')

class C(A):

def test(self):

print('from C')

class D(B):

def test(self):

print('from D')

class E(C):

def test(self):

print('from E')

class F(D,E):

# def test(self):

# print('from F')

pass

f1=F()

f1.test()

print(F.__mro__) #只有新式才有这个属性可以查看线性列表,经典类没有这个属性

#新式类继承顺序:F->D->B->E->C->A

#经典类继承顺序:F->D->B->A->E->C

#python3中统一都是新式类

#pyhon2中才分新式类与经典类

子类调用父类的方法

方法一:指名道姓,即父类名.父类方法()

# coding = gbk

class Vehicle: # 定义交通工具

country = 'China'

def __init__(self, name, speed, load, power):

self.name = name

self.speed = speed

self.load = load

self.power = power

def run(self):

print('GO,GO,GO')

class Subway(Vehicle):

def __init__(self, name, speed, load, power, line):

Vehicle.__init__(self ,name, speed, load, power)

self.line = line

def run(self):

print('%s %s线欢迎您!' % (self.name, self.line))

Vehicle.run(self)

Line4 = Subway('北京地铁', '200km/s', '1200人', '电', '13号')

Line4.run()

输出:

北京地铁 13号线欢迎您!

GO,GO,GO

方法二:super()

# coding = gbk

class Vehicle: # 定义交通工具

country = 'China'

def __init__(self, name, speed, load, power):

self.name = name

self.speed = speed

self.load = load

self.power = power

def run(self):

print('GO,GO,GO')

class Subway(Vehicle):

def __init__(self, name, speed, load, power, line):

#Vehicle.__init__(self ,name, speed, load, power) #原方式

super().__init__(name, speed, load, power) #python3中,super() 等同于 super(Subway, self)

self.line = line

def run(self):

print('%s %s线欢迎您!' % (self.name, self.line))

#Vehicle.run(self)

super().run()

Line4 = Subway('北京地铁', '200km/s', '1200人', '电', '13号')

Line4.run()

输出:

北京地铁 13号线欢迎您!

GO,GO,GO

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值