ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

第十一章 (补充)面向对象继承

2021-12-06 21:02:12  阅读:176  来源: 互联网

标签:obj 继承 第十一章 self 面向对象 pass print class def


目录

继承

继承简介

  1. 继承是一种创建新类的方式,新建的类可称为子类或派生类,父类可称为基类或超类
  2. python支持多继承,新建的类可以支持一个或多个父类
'''单继承和多继承简单定义'''
class Parent1:
    pass
class Parent2:
    pass
class Sub1(Parent1): #单继承
    pass
print(Sub1.__bases__)  # 查看自己的父类---->(<class '__main__.Parent1'>,)
 
class Sub2(Parent1,Parent2): # 多继承
    pass
print(Sub2.__bases__)    # 查看自己的父类---->(<class '__main__.Parent1'>, <class '__main__.Parent2'>)

经典类与新式类

在py2中有经典类和新式类的区别:

  • 新式类:继承了object类的子类,以及该子类的子类,子子类
  • 经典类:没有继承object类的子类,以及该子类的子类,子子类
'''py2中'''
class Foo:
    pass     # 经典类
class Bar(object):
    pass     # 新式类

注意:在py3中没有继承任何类,默认继承object类,所以python3中都是新式类

'''py3中'''
class Foo():
    pass
print(Foo.__bases__) # --->(<class 'object'>,),默认继承object类
 
class Sub(Foo):
    pass
 
print(Sub.__bases__) # ---->(<class '__main__.Foo'>,)

类继承解决了什么问题

  • 类解决对象与对象之间代码冗余的问题,子类可以遗传父类的属性
  • 继承解决的是类与类之间代码冗余的问题
  • object类丰富了代码的功能

示例如下:

'''学生选课系统和老师打分功能'''
# 学生类
class Student():
    def __init__(self,name,age,gender,course = None):
        self.name = name
        self.age = age
        self.gender = gender
        self.course = course
    # 定义一个选课的方法
    def choose_course(self,course):
        if self.course is None:
            self.course = []
        self.course.append(course)
        print(f"Student choice class --->{self.course}")
 
# 教师类
class Teacher():
    def __init__(self,name,age,gender,level):
        self.name = name
        self.age = age
        self.gender = gender
        self.level = level
    # 定义一个打分方法
    def make_score(self,stu_obj,score):
        stu_obj.score = score
        print(f'Teacher{self.name} make {stu_obj.score} to {stu_obj.name}! ')
    
'''有很多冗余的代码,优化一下,定义一个人的类整合一下重复的代码'''
# 人类
class Human():
    def __init__(self, name, age, gender):
        self.name = name
        self.age = age
        self.gender = gender
 
 
# 学生类
class Student(Human):
    def __init__(self, name, age, gender, score=None, course=None):
        Human.__init__(self, name, age, gender)
        self.score = score
        self.course = course
 
    # 定义一个选课的方法
    def choose_course(self, course):
        if self.course is None:
            self.course = []
        self.course.append(course)
        print(f"Student choice class --->{self.course}")
 
 
# 教师类
class Teacher(Human):
    def __init__(self, name, age, gender, level):
        Human.__init__(self, name, age, gender)
        self.level = level
 
    # 定义一个打分方法
    def make_score(self, stu_obj, score):
        stu_obj.score = score
        print(f'Teacher{self.name} make {stu_obj.score}marks to {stu_obj.name}! ')
 
 
# 学生类实例化
stu = Student('HammerZe', 18, 'male')
stu.choose_course('python')
 
# 教师类实例化
teacher = Teacher('li', 18, 'male', 10)
teacher.make_score(stu, 90)
 
Student choice class --->['python']
Teacherli make 90marks to HammerZe! 
 
 

多继承的优缺点

  • 优点:子类可以同时遗传多个父类的属性,最大限度的重用代码
  • 缺点:违反人的思维习惯,一个人有两个爹,代码的可读性会变差,不建议使用多继承,如果不可避免多个父类的继承,应该使用Mixins机制
  • 继承表达的是一种“是”什么关系

Mixins机制

  • 多继承的正确打开方式:mixins机制
  • mixins机制核心:就是在多继承背景下尽可能底提升多继承的可读性
  • 让多继承满足人的思维习惯--->什么“是”什么
class Vehicle:
    pass
class FlyableMixin:   # 规范多继承
    def fly(self):
        pass
# 民航飞机
class CiviAircraft(FlyableMixin,Vehicle)
	pass
#直升机
class Helicopter(FlyableMixin,Vehicle)
	pass
class Car(Vehicle)
	pass 
 
'''表达是的关系,放在继承的末尾,特们都是交通工具'''
 
'''eg:飞机有飞的功能,是交通工具'''
 
如果有多个功能就必须写多个Mixin类!

继承的查找顺序

  • 对象>子类>父类>父父类
  • 单继承背景下属性查找

示例如下:

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
 
'''查找顺序:
1.obj先从obj名称空间找,再从Bar名称空间中找,没有f2去他爹(Foo)中找
2.执行Foo中得f2,遇到self.f1()此时self是obj,是Bar的对象
3.执行Bar中的f1
'''
 
 
# 区别下:父类不想让子类的方法覆盖,可以私有化
class Foo:
    def __f1(self):  # _Foo__f1()
        print('Foo.f1')
 
    def f2(self):
        #
        print('Foo.f2')
        self.__f1()  # _Foo__f1()
 
 
class Bar(Foo):
    def __f1(self):  # # _Bar__f1()
        print('Bar.f1')
 
obj = Bar()
obj.f2()
 
# 结果
Foo.f2
Foo.f1
'''Foo中f1私有化,所以输出的是Foo中的f1'''

多继实现原理

菱形结构

在python中可以继承多个类,这样就会引发下面的结构:

  • 当D继承B和C,B、C分别继承A就会组成一个菱形的继承关系,这样就会涉及到查找属性的顺序问题,A、B、C、中如果方法重名,输出的顺序是按mro列表输出的顺序继承

示例如下:

'''py3中'''
 
class A():
    def out_text(self):
        print('from A')
 
class B(A):
    def out_text(self):
        print('from B')
 
class C(A):
    def out_text(self):
        print('from C')
 
class D(B,C):
    pass
 
obj = D()
obj.out_text() # 结果---->from B
''' 可以打印出mro列表查看顺序'''
print(D.mro())
# [<class '__main__.D'>,
# <class '__main__.B'>, 
# <class '__main__.C'>, 
# <class '__main__.A'>,
# <class 'object'>]
 
'''这样看来查找顺序就显而易见了,
1、从D中找out_text方法,没有直接去B
2、B中有out_text方法,直接输出停止查找'''
  • mro列表查找准则:
    1. 子类先查,再查父类
    2. 当继承多个父类的时候,按mro列表顺序被检查
    3. 如果继承多个类,被继承类内具有相同的方法,先输出mro列表左边类的方法
  • 注意:mro列表可以写成__mro__也可以,调用mro方法的必须是起始类,obj是D的对象,所以用D.mro()
  • mro列表是通过一个C3线性算法来实现的

非菱形结构


代码实现如下:

'''py3中'''
 
 
class E:
    pass
 
 
class F:
    pass
 
 
class B(E):
    pass
 
 
class C(F):
    pass
 
 
class D:
    def test(self):
        print('from D')
 
 
class A(B, C, D):
    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 D

深度优先和广度优先

深度优先:

  • 经典类:按深度优先查询

经典类查找顺序如下:


在py2中,没有继承object的类及其子类都是经典类

代码实现:

'''py2中'''
class G:
    def test(self):
        print('from G')
class E(G):
    def test(self):
        print('from E')
class F(G):
    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(G):
    def test(self):
        print('from D')
 
class A(B, C, D):
    pass
 
 
obj = A()
obj.test()  # 查找顺序为:obj->A->B->E->G->C->F->D->object
 
# 结果
from B

广度优先:

  • 新式类:按广度优先顺序查找

新式类查找顺序如下:

在py3中,默认为新式类

代码实现如下:

'''py3中'''
class G:
    def test(self):
        print('from G')
class E(G):
    pass
class F(G):
    pass
class B(E):
    pass
class C(F):
    pass
class D(G):
    def test(self):
        print('from D')
 
class A(B, C, D):
    pass
 
 
obj = A()
obj.test() # 查找顺序为:obj->A->B->E->C->F->D->G->object
 
# 结果
from D

super()方法

super()方法的存在就是为了解决多重继承的问题,在一个父类中使用super()方法用于调用下一个父类的方法

  • super方法
class A:
    def test(self):
        print('from A')
        super().test()
'''用于调用下一个父类的方法B.test'''
 
class B:
    def test(self):
        print('from B')
 
 
class C(A, B):
    pass
 
 
c = C()
c.test()
print(C.mro())
# 查找顺序如下
#[<class '__main__.C'>, <class '__main__.A'>, <class '__main__.B'>, <class 'object'>]
 
# 结果
from A
from B

抽象类

python的抽象类需要借助模块实现,抽象类是一个特殊的类,它只能被继承,不能被实例化

  • 作用:在不同的模块中通过抽象基类来调用,可以用最精简的方式展示出代码之间的逻辑关系,让模块之间的依赖清晰简单,使得代码的可读性变高。
  • 注意:子类继承抽象类的时候,必须定义相同方法对抽象类的方法进行覆盖
import abc
# 抽象类: 抽象类只能被继承,不能被实例化
class Animal(metaclass=abc.ABCMeta):
 
    @abc.abstractmethod  # 该方法已经是抽象方法了
    def speak(self): pass
 
    @abc.abstractmethod
    def login(self):pass
 
class People(Animal):
    def speak(self):
        print('嗷嗷嗷')
 
    def login(self):
        pass
 
 
class Pig(Animal):
    def speak(self):
        print('哼哼哼')
 
 
class Dog(Animal):
    def speak(self):
        print('汪汪汪')
 
 
obj = People()
obj.speak()

方法补充:

  1. sel.__class__查看对象所属类

  2. 类名/对象名.__dict__查看类/对象名称空间

  3. 类名/对象名.__bases__查看父类

  4. 起始类名.__mro__打印继承顺序,py3从左到右查找

  5. locals()查看局部名称空间

  6. globals()查看全局名称空间

  7. dirs(str)查看字符串所搭配的内置方法有哪些,查看内容可换


标签:obj,继承,第十一章,self,面向对象,pass,print,class,def
来源: https://www.cnblogs.com/haiqinai/p/15651803.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有