面向对象之继承

继承原理
对于你定义的每一个类,python会计算出一个方法解析顺序列表(MRO),这个列表就是一个简单的所有基类的线性顺序列表
当你需要调用类和每个父类的属性时,python会在mro列表上从左到右开始查找基类,直到找到第一个匹配这个属性的类
查找规则:
1.子类会先于父类被检查
2.多个父类会根据它们在列表中的顺序被检查
3.如果对下一个类存在两个合法的选择,选择第一个父类

继承顺序:
新式类:广度优先
经典类:深度优先
#新式类的继承,在查找属性时遵循  广度优先
class A(object):
    def test(self):
        print('from A')
    pass
class B(A):
    # def test(self):
    #     print('from B')
    pass
class C(A):
    # def test(self):
    #     print('from C')
    pass
class D(B):
    # def test(self):
    #     print('from D')
    pass

class E(C):
    # def test(self):
    #     print('from E')
    pass
class F(D,E):
    # def test(self):
    #     print('from F')
    pass
f1=F()

print(F.__mro__)
#广度优先:F->D->B->E->C->A->object


#python2 中经典类的继承,在查找属性时遵循  深度优先
class A:
    # def test(self):
    #     print('from A')
    pass
class B(A):
    # def test(self):
    #     print('from B')
    pass
class C(A):
    # def test(self):
    #     print('from C')
    pass
class D(B):
    # def test(self):
    #     print('from D')
    pass

class E(C):
    # def test(self):
    #     print('from E')
    pass
class F(D,E):
    # def test(self):
    #     print('from F')
    pass
f1=F()
f1.test()
#python2中经典类没有__mro__查询继承顺序的方法
# F->D->B->A->E->C
View Code 

#python3中
class B():
    def test(self):
        print('from B')
class C():
    def test(self):
        print('from C')
class D(B,C):
    def test(self):
        print('from D')
class E(B,C):
    def test(self):
        print('from E')
class F(D,E):
    def test(self):
        print('from F')

f = F()
f.test()
print(F.__mro__)
#F  D E B C
View Code

 


重用代码的两种方式

1.继承与派生 ‘是’的关系
先抽象再继承,是基于抽象的结果,通过编程语言去实现它,肯定是先经历抽象这个过程,才能通过继承这个方式去表达出
抽象的结构
派生有两种形式:1是父类有的函数,子类可以使用,同时可以定义自己独有的函数
# #重用代码的两种方式:
# #继承与派生      ‘是’的关系
class Hero:
    def __init__(self,nickname,aggressivity,life_value):
        self.nickname = nickname
        self.aggressivity = aggressivity
        self.life_value = life_value
    def attack(self,enemy):
        print('hero attack')
        enemy.life_value -= self.aggressivity

class Garen(Hero):
    n = 0
    def __init__(self,nickname,aggressivity,life_value,script):
        Hero.__init__(self,nickname,aggressivity,life_value)
        self.script = script
        Garen.n += 1
    def attack(self,enemy):
        Hero.attack(self,enemy)
        print('Garen attack')

g1 = Garen('草丛伦',115,500,'人在塔在')
print(g1.nickname)
print(g1.aggressivity)
print(g1.life_value)
print(g1.script)
print(g1.__dict__)
View Code

 


2是父类有的函数,子类的函数与之重名,对象就只能使用所属类的函数,
但可以设置在子类中调用父类的函数来使对象可以同时使用类和父类的函数
                       子类中调用父类的方法:super

使用super调用的所有属性,都是通过mro列表当前的位置往后找


经典类没有mro方法,经典类没有super这个方法
正因为经典类没有mro列表,不能计算继承顺序,所以不能使用super
#coding : utf8

#子类继承父类属性的方法: super
#python3中      都是新式类
class People:
    def __init__(self,name,age,sex):
        self.name = name
        self.age = age
        self.sex = sex
    def walk(self):
        print('%s is walking '%self.name)
class Chinese(People):
    country = 'china'
    def __init__(self,name,age,sex,language='chinese'):
        super().__init__(name,age,sex)
        self.language = language
    def walk(self):
        super().walk()
        print("==========>")

c = Chinese('egon',22,'male')
print(c.age)
c.walk()

#super在python2中的用法
    #1 super(自己的类,self).父类的函数名字
    #2 super 只能用于新式类
class People(object):
    def __init__(self,name,age,sex):
        self.name = name
        self.age = age
        self.sex = sex
    def walk(self):
        print('%s is walking '%self.name)
class Chinese(People):
    country = 'china'
    def __init__(self,name,age,sex,language='chinese'):
        super(Chinese,self).__init__(name,age,sex)
        self.language = language
    def walk(self):
        super(Chinese,self).walk()
        print("==========>")


c = Chinese('egon',22,'male')
print(c.age)
c.walk()
View Code

 


2.组合 ‘有’的关系
在一个类中以另外一个类的对象作为数据属性,称为类的组合
可以在不改变原有类的代码的基础上,为对象增加功能
#组合       ‘有’的关系
class Teacher:
    def __init__(self,name,sex,course):
        self.name = name
        self.sex = sex
        self.course = course
class Student:
    def __init__(self,name,sex,course):
        self.name = name
        self.sex = sex
        self.course = course
class Course:
    def __init__(self,name,price,period):
        self.name = name
        self.price = price
        self.period = period
c1 = Course('python',15800,'7m')
t1 = Teacher('egon','male',c1)
s1 = Student('cobila','male',c1)

print(t1.course.name)
View Code

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


继承的两种用途
1继承父类的方法,并且做出自己的改变和派生
2接口继承:声明某个子类兼容于某父类,定义一个接口类函数,接口类中定义了一些接口名(函数名)且并未实现接口的功能
子类继承接口类并且实现接口中的功能


什么是接口
接口继承实质上是要求:做出一个良好的抽象,这个抽象规定了一个兼容接口,使得外部调用者无需关心具体细节,可一视同仁的处理
实现了特定接口的所有对象

为什么要用接口
因为要实现归一化: 只要是基于同一个接口实现的类,那么所有的这些类产生的对象在使用时都是一样的
归一化的意义:让使用者无需关心对象的类是什么,只需要知道,这些对象都具备了某些功能就可以了
这极大降低了使用者的使用难度。
# #接口与归一化
class Animal:
    def run(self):
        raise AttributeError('子类必须要实现这个方法')
    def speak(self):
        raise AttributeError('子类必须要实现这个方法')

class Person(Animal):
    def run(self):
        print('person walking')

class Pig(Animal):
    def speak(self):
        print('pig speaking')

person1 = Person()
person1.run()
pig1 = Pig()
pig1.speak()
person1.speak()
View Code

 


抽象类
抽象类就是从一堆类中抽取相同的内容而来的,只有抽象方法,没有实现功能,所以不能被实例化
抽象类与接口的区别
接口是用来实现的,抽象类是用来继承的

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

抽象类本质还是类,与普通类额外的特点是:加了装饰器的函数,只能被继承,子类必须实现他们

抽象类是一个介于类和接口之间的一个概念,同时具备类和接口的部分特性,可以用来实现归一化设计
# #抽象类
import abc
class Animal(metaclass=abc.ABCMeta):
    @abc.abstractmethod
    def run(self):
        pass
    @abc.abstractmethod
    def speak(self):
        pass

class Person(Animal):
    def run(self):
        print('person walking')
    def speak(self):
        print('person speaking')
class Pig(Animal):
    def speak(self):
        print('pig speaking')

person1 = Person()
#animal = Animal()           抽象类不能被实例化
View Code

 

 
posted @ 2017-04-23 09:33  柳姑娘  阅读(142)  评论(0)    收藏  举报