继承与多态

继承

1.什么是继承

I:继承就是一种创建新类的方式,新建的类可以称为子类或者派生类,父类可以称为基类或超类,子类会遗传父类的属性

II:需要注意的是:python支持多继承
    在python中,新建的类可以继承一个或多个父类

class Parent1(object):
    x=1111

class Parent2(object):
    pass

class Sub1(Parent1): # 单继承
    pass

class Sub2(Parent1,Parent2): # 多继承
    pass

我们可以通过__base__方法来查看该类的父类

print(Sub1.__bases__) #  (<class '__main__.Parent1'>,)
print(Sub2.__bases__) #  (<class '__main__.Parent1'>, <class '__main__.Parent2'>)
print(Sub1.x) # 1111

ps1:在python2中有经典类与新式类之分

新式类:继承了objecct类的子类,以及孩子类的子类子子类

经典类:没有继承object类的子类,以及孩子类的子类子子类

ps2:在python3中没有继承任何类,那么会默认继承object类,所以python3中所有的类都是新式类

print(Parent1.__bases__) # (<class 'object'>,)
print(Parent2.__bases__) # (<class 'object'>,)

III:python的多继承

优点:子类可以同时遗传多个父类的属性,最大限度地重用代码

缺点:

        1.违背人的思维习惯,继承表达的是一种"什么"是"什么"的关系
        2.代码可读性会变差
        3.不建议使用多继承,有可能会引发可恶的菱形问题,扩展性变差
        如果真的涉及到一个子类不可避免地要重用多个父类的属性,应该使用Mixins

2.为什么要用继承:用来解决类与类之间代码冗余问题

3.如何实现继承

示例1:解决类与类之间存在的冗余问题

class Student:
    school='OLDBOY'
    def __init__(self,name,age,sex):
        self.name=name
        self.age=age
        self.sex=sex

    def choose_course(self):
        print('学生%s 正在选课' %self.name)
class Teacher:
    school='OLDBOY'

    def __init__(self,name,age,sex,salary,level):
        self.name=name
        self.age=age
        self.sex=sex
        self.salary=salary
        self.level=level

    def score(self):
        print('老师 %s 正在给学生打分' %self.name)

示例2 基于继承解决类与类之间的冗余问题

class OldboyPeople:
    school = 'OLDBOY'

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

class Student(OldboyPeople):
    def choose_course(self):
        print('学生%s 正在选课' % self.name)

        
class Teacher(OldboyPeople):
    #           老师的空对象,'egon',18,'male',3000,10
    def __init__(self, name, age, sex, salary, level):
        # 指名道姓地跟父类OldboyPeople去要__init__
        OldboyPeople.__init__(self,name,age, sex)
        self.salary = salary
        self.level = level

    def score(self):
        print('老师 %s 正在给学生打分' % self.name)

tea_obj=Teacher('egon',18,'male',3000,10)

单继承下的属性查找

有了继承关系,对象在查找属性时,先从对象自己的__dict__中找,如果没有则去子类中找,然后再去父类中找

示例一:

class Foo:
    def f1(self):
        print('Foo.f1')
    def f2(self):
        print('Foo.f2')
        self.f1()

class Bar(Foo):
    def f1(self):
        print('Bar.f1')

obj=Bar()
obj.f2()
# Foo.f2
# Bar.f1
# b.f2()会在父类Foo中找到f2,先打印Foo.f2,然后执行到self.f1(),即b.f1(),仍会按照:对象本身->类Bar->父类Foo的顺序依次找下去,在类Bar中找到f1,因而打印结果为Foo.f1

示例二:父类如果不想让子类覆盖自己的方法,可以采用双下划线开头的方式将方法设置为私有的

class Foo:
    def __f1(self): # _Foo__f1
        print('Foo.f1')

    def f2(self):
        print('Foo.f2')
        self.__f1() # self._Foo__f1,# 调用当前类中的f1

class Bar(Foo):
    def __f1(self): # _Bar__f1
        print('Bar.f1')

obj=Bar()
obj.f2()

多继承带来的菱形问题

一:菱形问题介绍与MRO

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,C):
    pass

print(C.mro()) # 类C以及类C的对象访问属性都是参照该类的mro列表
# [<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>] 
obj = D()
obj.test() # 结果为:from B

总结:类相关的属性查找(类名.属性, 该类的对象.对象),都是参照该类的mro

二:如果多继承是非菱形继承,经典类与新式的属性查找顺序一样:
    都是一个一个分支的找下去,然后最后找object

class E:
    def test(self):
        print('from E')
class F:
    def test(self):
        print('from F')
class B(E):
    def test(self):
        print('from B')
class C(F):
    def test(self):
        print('from C')
class D:
    def test(self):
        print('from D')
class A(B, C, D):
    # def test(self):
    #     print('from A')
    pass
print(A.mro())
'''
[<class '__main__.A'>, <class '__main__.B'>, <class '__main__.E'>, <class '__main__.C'>, <class '__main__.F'>, <class '__main__.D'>, <class 'object'>]
'''

obj = A()
obj.test() # 结果为:from B
# 可依次注释上述类中的方法test来进行验证

三:如果多继承是菱形继承,经典类与新式类的属性查找顺序不一样:

经典类:深度优先,会在检索第一条分支的时候就直接一条道走到黑,即会检索共同的父类

新式类:广度优先,会在检索最后一条分支的时候检索共同的父类

class G: # 在python2中,未继承object的类及其子类,都是经典类
    # def test(self):
    #     print('from G')
    pass

class E(G):
    # def test(self):
    #     print('from E')
    pass

class F(G):
    def test(self):
        print('from F')

class B(E):
    # def test(self):
    #     print('from B')
    pass

class C(F):
    def test(self):
        print('from C')

class D(G):
    def test(self):
        print('from D')

class A(B,C,D):
    # def test(self):
    #     print('from A')
    pass

# 新式类
# print(A.mro()) # A->B->E->C->F->D->G->object

# 经典类:A->B->E->G->C->F->D
obj = A()
obj.test()

在子类派生的新方法中如何重用父类的功能

方式一:知名道姓的调用某一个类下的函数,不依赖于继承关系

class OldboyPeople:
    def __init__(self,name,age,sex):
        self.name=name
        self.age=age
        self.sex=sex

    def f1(self):
        print('%s say hello' %self.name)

class Teacher(OldboyPeople):
    def __init__(self,name,age,sex,level,salary):
        OldboyPeople.__init__(self,name,age,sex)
        self.level = level
        self.salary=salary

tea_obj=Teacher('egon',18,'male',10,3000)
print(tea_obj.__dict__)

方式二:super()调用父类提供给自己的方法=》严格依赖继承关系

调用super()会得到一个特殊的对象,该对象会参照发起属性查找的那个类的mro,去当前类的父类中找属性

class A:
    def text(self):
        super().text()

class B:
    def text(self):
        print('from b')


class C(A,B):
    pass

obj=C()
obj.text() # from b
print(C.mro()) # [<class '__main__.C'>, <class '__main__.A'>, <class '__main__.B'>, <class 'object'>]

多态与鸭子类型

1.什么是多态

同一种事物有多种形态

class Animal:
    pass
class People(Animal):
    pass
class Dog(Animal):
	pass
class Pig(Animal):
    pass

2.为何要有多态=》多态会带来什么样的特性,多态性

多态性指的是可以在不考虑对象具体类型的情况下而直接使用对象
多态性的好处在于增强了程序的灵活性和可扩展性

class Animal:
    def say(self):
        print('动物基本发声频率    ',end='')

class People(Animal):
    def say(self):
        super().say()
        print('嘤嘤嘤')

class Dog(Animal):
    def say(self):
        super().say()
        print('汪汪汪')
class Pig(Animal):
    def say(self):
        super().say()
        print('哼哼哼')

obj1=People()
obj2=Dog()
obj3=Pig()

obj1.say()
obj2.say()
obj3.say()

定义统一的接口,接受传入的动物对象

def animal(animal):
    animal.say()

animal(obj1)
animal(obj2)
animal(obj3

python推崇的是鸭子类型:“如果看起来像、叫声像而且走起路来像鸭子,那么它就是鸭子”
鸭子类型在某种程度上实现了程序的松耦合度

# 二者看起来都像文件,因而就可以当文件一样去用,然而它们并没有直接的关系
class Txt: # Txt类有两个与文件类型同名的方法,即read和write
    def read(self):
        pass
    def write(self):
        pass

class Disk: # Disk类也有两个与文件类型同名的方法:read和write
    def read(self):
        pass
    def write(self):
        pass
    
# 了解:
import abc

class Animal(metaclass=abc.ABCMeta): # 统一所有子类的标准
    @abc.abstractmethod
    def say(self):
        pass

# obj=Animal() # 不能实例化抽象类自己

class People(Animal):
    def say(self):
        pass

class Dog(Animal):
    def say(self):
        pass

class Pig(Animal):
    def say(self):
        pass

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值