继承:继承是一种创建新类的方式,在Python中,新建的类可以继承一个或多个父类,父类又可以称为基类或超类,新建的类称为子类或派生类;
class A:pass class B:pass class A_son(A,B):pass # 可以继承多个类 class B_son(B):pass # 可以继承一个类 # 两个子类之间是没有关联的
注意:什么时候用组合,什么时候用继承
组合:什么有什么的关系 继承:什么是什么的关系
Python中类的继承分为单继承和多继承。注意:常用单继承,多继承主要用在设计模式里--接口类
查看继承的方法:__base__ 和 __bases__
__base__ : 只查看从左到右继承的第一个子类;
__bases__: 查看所有继承的父类;
# 查看子类继承了那些父类:__bases__ class A:pass class B(object):pass class A_son(A,B):pass class B_son(B):pass print(A_son.__bases__) # 查看继承了那个类 print(B_son.__bases__) print(A.__bases__) # 默认继承object # 在Python 3 中没有继承父类的,默认继承 object ---新式类 print(B.__bases__)
注意:如果一个类没有指定一个父类(基类或超类),那么默认继承一个叫object的类,object是所有Python类的父类(基类或超类),它提供了一些常用的方法(如:__str__的实现);在Python2.7里需要需添加object类才能成为新式类,否者就是经典类;在Python3中所有的类都是新式类;
# 例子 class Default_info: def __init__(self,name,age): self.name = name self.age = age class Boy(Default_info): sex = '男' def msg(self): print('是一位男生') class Girl(Default_info): sex = '女' def msg(self): print('是一位女生') jerry = Boy('Jerry',18) amy = Girl('Amy',18) print(jerry.name) print(amy.age)
继承与抽象
抽象即抽取类似或比较像的部分。
抽象分成两个层次:
1、将奥巴马和梅西这俩对象比较像的部分抽取成类;
2、将人,狗,猪这三个雷比较像的部分抽取成父类(基类或超类);
抽象最主要的作用是划分类别(可以隔离关注点,降低复杂度)
继承:是基于抽象的结果,通过编程语言去实现它,肯定是先经历抽象这个过程,才能通过继承的方式去表达出抽象的结构。
抽象只是分析和设计的过程中,一个动作或者说一种技巧,通过抽象可以得到类。
class Animal: def animal_type(self): print('这是Animal类:',type(self)) # 运行后发现这里的self接收的是子类传过来的self print('%s的种类是:动物'%self) print('%s的种类是:动物'%self.name) class Person(Animal): def username(self,name): print('这是Person类:',type(self)) self.name = name print('人的名字是%s!'%name) class Pig: def pigname(self,name): print('猪的名字是%s!'%name) class Dog: def dogname(self,name): print('狗的名字是%s!'%name) # 实例化 peole = Person() peole1 = Person() # 对象调用类的方法 peole.username('奥巴马') peole1.username('梅西') # 测试是否继承共有的属性 peole.animal_type() peole1.animal_type()
继承与重用性
在开发过程中,如果我们定义了一个类A,然后又想新建立另外一个类B,但是类B的大部分内容与类A的相同,如果类B再写一个和类A相同的东西,那么就造就了代码的累赘和重复,解决这个我们就用到了类的继承的概念。通过继承的方式新建类B,让B继承A,类B会'遗传'A的所有属性(数据属性和函数属性),实现代码的重用。
==========================第一部分 例如 猫可以:吃、喝、爬树 狗可以:吃、喝、看家 如果我们要分别为猫和狗创建一个类,那么就需要为 猫 和 狗 实现他们所有的功能,伪代码如下: #猫和狗有大量相同的内容 class 猫: 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 ==========================第二部分 上述代码不难看出,吃、喝是猫和狗都具有的功能,而我们却分别的猫和狗的类中编写了两次。如果使用 继承 的思想,如下实现: 动物:吃、喝 猫:爬树(猫继承动物的功能) 狗:看家(狗继承动物的功能) 伪代码如下: class 动物: 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): print ("%s 喝 " %self.name) class Cat(Animal): def __init__(self, name): self.name = name self.breed = '猫' def climb(self): print('爬树') class Dog(Animal): def __init__(self, name): self.name = name self.breed='狗' def look_after_house(self): print('汪汪叫') # ######### 执行 ######### c1 = Cat('小白家的小黑猫') c1.eat() c2 = Cat('小黑的小白猫') c2.drink() d1 = Dog('胖子家的小瘦狗') d1.eat()
继承的重用性例子
注意:用已经有的类金莲一个新的类,这样就重用了已经有的软件中的一部分设置大部分,大大减轻了编程的工作量,这就是常说的软件重用,不仅可以重用自己的类,也可以继承别人的。比如标准库,来定制新的数据类型,这样就可以大大的缩减软件开发周期,对大型软件开发来说意义重大。
笔者自己有个疑问,什么时候适合在父类使用__init__,什么时候适合在子类中使用__init__,实例化,调用是否有差异?
# 例子:在一个人员信息里,人与人之间有同样属性的东西:名字,年龄,职位,以性别为区分 class All_info: def info(self,name,age,job): self.name = name self.age = age self.job = job print(''' 姓名:%s 年龄:%s 职位:%s '''%(name,age,job)) class Men(All_info): def sex(self): print('性别:男') class Women(All_info): def sex(self): print('性别:女') jerry = Men() jerry.info('Jerry',18,'IT') jerry.sex()
未使用__init__
# 例子:在一个人员信息里,人与人之间有同样属性的东西:名字,年龄,职位,以性别为区分 class All_info: def __init__(self,name,age,job): self.name = name self.age = age self.job = job print(''' 姓名:%s 年龄:%s 职位:%s '''%(name,age,job)) class Men(All_info): def sex(self): print('性别:男') class Women(All_info): def sex(self): print('性别:女') jerry = Men('Jerry',18,'IT') jerry.sex()
使用__init__
派生
父类仲没有的属性,在子类仲出现,叫做派生属性
父类中没有的方法,在子类中出现,叫做派生方法
只要是子类的对象低啊用,子类中有的名字,一定用子类,子类中没有才找父类,如果父类也没有就报错
如果父类,子类都有,就一定用子类
如果还想用父类的,单独调用父类的,需要自己传self参数
# 父类名.方法名 需要自己传self参数 # super().方法名 不需要自己传self
class Animal: ''' 人和狗都是动物,所以创造一个Animal基类 ''' def __init__(self, name, aggressivity, life_value): self.name = name # 人和狗都有自己的昵称; self.aggressivity = aggressivity # 人和狗都有自己的攻击力; self.life_value = life_value # 人和狗都有自己的生命值; def eat(self): print('%s is eating'%self.name) class Dog(Animal): ''' 狗类,继承Animal类 ''' def bite(self, people): ''' 派生:狗有咬人的技能 :param people: ''' people.life_value -= self.aggressivity class Person(Animal): ''' 人类,继承Animal ''' def attack(self, dog): ''' 派生:人有攻击的技能 :param dog: ''' dog.life_value -= self.aggressivity egg = Person('egon',10,1000) ha2 = Dog('二愣子',50,1000) print(ha2.life_value) print(egg.attack(ha2)) print(ha2.life_value)
注意:像ha2.life_value之类的属性引用,会先从实例中找life_value然后去类中找,然后再去父类中找...直到最顶级的父类。
多继承
多继承:子类有多个父类
class A: def func(self):print('A') class B: def func(self):print('B') class C: def func(self):print('C') class D(A,B,C): def func(self):print('D') d = D() d.func() #情况1、注释D的方法 class A: def func(self):print('A') class B: def func(self):print('B') class C: def func(self):print('C') class D(A,B,C): pass #def func(self):print('D') d = D() d.func() #情况二、把A的方法注释 class A: pass # def func(self):print('A') class B: def func(self):print('B') class C: def func(self):print('C') class D(A,B,C): pass # def func(self):print('D') d = D() d.func()
钻石继承
# python 3 中所有新式类 都是采用广度优先 class A: def func(self):print('A') class B(A): pass #def func(self):print('B') class C(A): pass #def func(self):print('C') class D(B,C): pass #def func(self):print('D') d = D() d.func() # 虽然遵守广度优先,但是也走深度优先 class A: def func(self):print('A') class B(A): pass #def func(self):print('B') class E: def func(self):print('E') class C(E): pass #def func(self):print('C') class D(B,C): pass #def func(self):print('D') d = D() d.func()
菱形继承
class A: def func(self):print('A') class F(A): pass # def func(self):print('F') class B(F): pass #def func(self):print('B') class E(A): pass #def func(self):print('E') class C(E): pass #def func(self):print('C') class D(B,C): pass #def func(self):print('D') d = D() d.func()
# mro() -- 记录继承的顺序 print(D.mro())
新式类的继承顺序:广度优先
Python2.7就有经典类:深度优先
多继承中,我们子类的对象低啊用一个方法,默认是就近原则,找的顺序是什么?
经典类中-->深度优先
新式类中-->广度优先
python2.7 新式类和经典类共存,新式类要继承object
python3 只有新式类,默认继承object
经典类和新式类的区别是
super()只在python3中存在
mro() 只在新式类中存在
super() 方法进阶
super的本质:不是直接找父类,而是根据调用者的节点位置的广度优先顺序来的。
class A: def func(self):print('A') class B(A): def func(self): super().func() print('B') class C(A): def func(self): super().func() print('C') class D(B,C): def func(self): super().func() print('D') d = D() d.func()
class A: def func(self):print('A') class B(A): def func(self): super().func() print('B') class C(A): def func(self): super().func() print('C') class D(B,C): def func(self): super().func() print('D') b = B() b.func()