day30

news2024/9/30 5:24:43

今日内容概要

  • 继承(面向对象中得核心)

    • 单继承 多继承

  • 单继承下的属性查找

  • 多继承下的属性查找

  • super和mro的使用

  • 多态和鸭子类型

继承(核心)

面向对象的三大特征:封装、继承、多态

1.什么是继承

继承就是一种新建类的方式,新建出来的类我们称为‘子类或者叫派生类’,被继承的类我们称之为是‘父类或者基类’

   当然出来的类子类可以遗传父类的所有属性

2.为什么要用继承

类解决了什么问题:对象与对象之间的代码冗余问题

继承解决了什么问题:类与类之间的代码冗余问题

3.怎么使用继承

经典类:没有继承object类的子子孙孙类都是经典类

新式类:继承了object类的子子孙孙类都是新式类

只有在python2中才区分经典类和新式类,如果是python3的版本,所有类都是新式类,也就是说在python3中默认的类都是继承了object类,在python3中没有了经典类和新式类的说法了

 class Parent1:
    pass


class Parent2(object):
    pass

”Sub1继承了Parent1的类,Sub1就称为是子类,Parent1类就称为是父类或者叫基类“

单继承:一个类只继承了一个类,一个类继承了两个或者两个以上的类就是多继承了

class Sub1(Parent1):
    pass

多继承的类:Sub2就是子类,Parent1和Parent2都是父类

class Sub2(Parent1, Parent2):
    pass

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

继承的实际案例

class People():
    school = 'SH'
    def __init__(self, name, age, gender):
        self.name = name
        self.age = age
        self.gender = gender

class Student(People):
    def __init__(self, name, age, gender, course=None):
        if course is None:
            course = []
        """子类里面一定再次调用父类的__init__方法"""
        People.__init__(self, name, age, gender) # 指名道姓的调用方法
        self.course = course

    def choose_course(self):
        print('%s 选课成功, %s' % (self.name, self.course))


stu = Student('ly', 20, 'male')
print(stu.school)  # SH 属性的查找
print(stu.name)
print(stu.age)
print(stu.gender)


class Teacher(People):
    def __init__(self, name, age, gender, level):
        People.__init__(self, name, age, gender)
        self.level = level

    def score(self, stu_name):
        print('%s 得了%s分' % (stu_name, 10))

tea = Teacher('kevin', 19, 'female')
print(tea.name)
print(tea.age)
print(tea.gender)

属性查找

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

>>> class Foo:
...     def f1(self):
...         print('Foo.f1')
...     def f2(self):
...         print('Foo.f2')
...         self.f1()
... 
>>> class Bar(Foo):
...     def f1(self):
...         print('Foo.f1')
... 
>>> b=Bar()
>>> b.f2()
Foo.f2
Foo.f1

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

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

>>> class Foo:
...     def __f1(self): # 变形为_Foo__fa
...         print('Foo.f1') 
...     def f2(self):
...         print('Foo.f2')
...         self.__f1() # 变形为self._Foo__fa,因而只会调用自己所在的类中的方法
... 
>>> class Bar(Foo):
...     def __f1(self): # 变形为_Bar__f1
...         print('Foo.f1')
... 
>>> 
>>> b=Bar()
>>> b.f2() #在父类中找到f2方法,进而调用b._Foo__f1()方法,同样是在父类中找到该方法
Foo.f2
Foo.f1

继承的实现原理

菱形问题

大多数面向对象语言都不支持多继承,而在python中,一个子类是可以同时继承多个父类的,这固然可以带来一个子类可以对多个不同父类加以重用的好处,但也有可能引发著名的Diamond problem菱形问题(或称钻石问题,有时候也被称为“死亡钻石”),菱形其实就是对下面这种继承结构的形象比喻

 A类在顶部,B类和C类分别位于其下方,D类在底部将两者连接在一起形成菱形。

这种继承结构下导致的问题称之为菱形问题:如果A中有一个方法,B和/或C都重写了该方法,而D没有重写它,那么D继承的是哪个版本的方法:B的还是C的?如下所示

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


obj = D()
obj.test() # 结果为:from B

要想搞明白obj.test()是如何找到方法test的,需要了解python的继承实现原理

继承原理

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

>>> D.mro() # 新式类内置了mro方法可以查看线性列表的内容,经典类没有该内置该方法
[<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>]

python会在MRO列表上从左到右开始查找基类,直到找到第一个匹配这个属性的类为止。而这个MRO列表的构造是通过一个C3线性化算法来实现的。我们不去深究这个算法的数学原理,它实际上就是合并所有父类的MRO列表并遵循如下三条准则:

1.子类会先于父类被检查
2.多个父类会根据它们在列表中的顺序被检查
3.如果对下一个类存在两个合法的选择,选择第一个父类

所以obj.test()的查找顺序是,先从对象obj本身的属性里找到方法test,没有找到,则参照属性查找的发起者(即obj)所处类D的MRO列表来依次检索,首先在类D中未找到,然后再B中找到方法test

1.由对象发起的属性查找,会从对象自身的属性里检索,没有则会按照对象的类.mro()规定的顺序依次找下去,
2.由类发起的属性查找,会按照当前类.mro()规定的顺序依次找下去,

深度优先和广度优先

参照下述代码,多继承结构为非菱形结构,此时,会按照先找B这一条分支,然后再找C这一条分支,最后找D这一条分支的顺序直到找到我们想要的属性

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来进行验证

 如果继承关系为菱形结构,那么经典类与新式类会有不同MRO,分别对应属性的两种查找方式:深度优先和广度优先

class G: # 在python2中,未继承object的类及其子类,都是经典类
    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):
    # def test(self):
    #     print('from A')
    pass

obj = A()
obj.test() # 如上图,查找顺序为:obj->A->B->E->G->C->F->D->object
# 可依次注释上述类中的方法test来进行验证,注意请在python2.x中进行测试

 

 

class G(object):
    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):
    # def test(self):
    #     print('from A')
    pass

obj = A()
obj.test() # 如上图,查找顺序为:obj->A->B->E->C->F->D->G->object
# 可依次注释上述类中的方法test来进行验证

super的使用

#A没有继承B,但是A内super会基于C.mro()继续往后找
class A:
    def test(self):
        super().test()
class B:
    def test(self):
        print('from B')
class C(A,B):
    pass

c=C()
c.test() #打印结果:from B

多态和鸭子类型

多态它是面向对象的三大特征之一

什么是多态?  同一种事物的多种形态

举例:

    水:气态水、液态水、固态水                                                                                                             动物:人 鸡 狗 猪等都是动物的一种形态

之所以说人、鸡、狗、猪是动物,是因为他们具备动物的特征,speak功能

import abc # abstract class 抽象类   具体的Specific

class Animal(metaclass=abc.ABCMeta): # 把animal类变成了抽象类
    """父类中得方法不是为了实现逻辑的,实现功能的,而是单纯的为了限制子类的行为"""
    @abc.abstractmethod # 把抽象类中得方法变成抽象方法, 它不实现具体的功能,就是单纯的为了限制子类中的方法
    def speak(self):
        pass
    @abc.abstractmethod
    def jiao(self):
        pass


"""抽象类和普通类有什么区别? 抽象类只能够被继承、不能够被实例化"""

# Animal() # Can't instantiate abstract class Animal with abstract methods speak

"""怎么限制子类People类必须有speak功能? 我们可以在父类中来限制子类的行为,其实就是限制子类中必须有某些方法"""


"""Python崇尚的是鸭子类型"""

"""鸭子类型就是更多的关注的是对象的行为,而不是对象的类型"""

class People(Animal):
    def speak(self):pass
        # print('from People.speak')
    def jiao(self):
        pass

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


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

"""多态带来的特性:在不考虑对象类型的情况下,直接调用对象的方法或者属性"""
def animal(obj):
    return obj.speak()

animal(obj)
animal(obj1)
animal(obj2)

"""面试题:请举出Python中使用多态的例子:len"""

len('hello')
len([1,2,3,4])
len((1,2,3,4))


def len(obj):
    return obj.__len__
len('helloworld')
len([1,2,3,4])
len((1,2,3,4))

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1072985.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Bootstrap的宽度和高度的设置(相对于父元素的宽度和高度、相对于视口的宽度和高度)

在Bootstrap中&#xff0c;宽度和高度的设置分为两种情况&#xff0c;一种是相对于父元素的宽度和高度设置&#xff0c;以百分比来表示&#xff1b;另一种是相对于视口的宽度和高度设置&#xff0c;单位为vw(视口宽度)和vh(视口高度)。 01-相对于父元素的宽度和高度设置 示例…

Ubuntu磁盘满了,导致黑屏

前言 &#xff08;1&#xff09;最近要玩Milk-V Duo&#xff0c;配置环境过程中&#xff0c;发现磁盘小了。于是退出虚拟机&#xff0c;扩大Ubuntu大小&#xff0c;重新开机&#xff0c;发现无法进入Ubuntu界面。 &#xff08;2&#xff09;查了很久&#xff0c;后面发现是磁盘…

软件测试之压力测试详解

压力测试 压力测试是一种软件测试&#xff0c;用于验证软件应用程序的稳定性和可靠性。压力测试的目标是在极其沉重的负载条件下测量软件的健壮性和错误处理能力&#xff0c;并确保软件在危急情况下不会崩溃。它甚至可以测试超出正常工作点的测试&#xff0c;并评估软件在极端…

外汇天眼:外汇投资小白必读! 4大外汇交易常见提问释疑

近年来外汇市场急速发展&#xff0c;加上科技不断进步&#xff0c;只要通过手机就能随时随地进行交易&#xff0c;因此吸引愈来愈多投资人参与&#xff0c;无论目的是资产多元配置还是避险&#xff0c;都进一步增加市场的流动性与热络程度。因此考虑想要投资外汇&#xff0c;很…

VUE(递归)语法没错,但报 ESLint: ‘formatToTree‘ is not defined.(no-undef)

原因&#xff1a;ESLint(JavaScript 检查器)不允许有未定义的函数&#xff0c;但在递归语法中&#xff0c;自身需要调用自身&#xff0c;则嵌套在里面的函数就会被认为是没定义。 解决办法&#xff1a; 在项目根目录下找到.eslintrc.js文件&#xff0c;文件路径如下图&#xff…

红队专题-Cobalt strike从小白到飞升手册

红队专题 招募六边形战士队员Cobalt strike渗透测试先进威胁战术介绍使用注意事项 架构Listener(监听器)Foreign Listeners &#xff08;外部监听器&#xff09;Pivot Listeners BeaconBeacon 的安全特性stager下载stagestage准备check in从Team Server下载任务返回任务结果 Be…

springboot家乡特色推荐系统springboot28

大家好✌&#xff01;我是CZ淡陌。一名专注以理论为基础实战为主的技术博主&#xff0c;将再这里为大家分享优质的实战项目&#xff0c;本人在Java毕业设计领域有多年的经验&#xff0c;陆续会更新更多优质的Java实战项目&#xff0c;希望你能有所收获&#xff0c;少走一些弯路…

《计算机网络:自顶向下方法》第六章--链路层和局域网

网络层提供了任意两台主机之间的通信服务。在两台主机之间&#xff0c;数据报跨越一系列通信链路传输&#xff0c;&#xff08;一些是有线链路&#xff0c;一些是无线链路&#xff09;从源主机开始&#xff0c;通过一系列分组交换机到达目的主机 链路层中有两种不同类型的链路…

当 AI 成为“逆子”;强化学习之父联手传奇程序员丨 RTE 开发者日报 Vol.62

开发者朋友们大家好&#xff1a; 这里是 「RTE 开发者日报」 &#xff0c;每天和大家一起看新闻、聊八卦。我们的社区编辑团队会整理分享 RTE &#xff08;Real Time Engagement&#xff09; 领域内「有话题的 新闻 」、「有态度的 观点 」、「有意思的 数据 」、「有…

MongoDB-介绍与安装部署

介绍与安装部署 1.MongoDB简介a) 体系结构b) 数据模型c) MongoDB的特点c.1) 高性能c.2) 高性可用性c.3) 高拓展性c.4) 丰富的查询支持 2.单机部署a) Windows系统中的安装启动b) Shell连接(mongo命令)c) Linux系统中的安装启动和连接 1.MongoDB简介 MongoDB是一个开源、高性能、…

OpenSSL安装过程总结

1 OpenSSL是什么及怎么用 参考: openssl中文手册 2 下载源文件 Github&#xff1a; https://github.com/openssl/openssl 官网&#xff1a; https://www.openssl.org/source/ 3 安装 先查看README.md文档&#xff0c;根据描述找到自己对应平台的NOTES-*.md文档和INSTALL.m…

RunnerGo亮相QECon大会上海站,来看看这款全栈测试平台

QECon&#xff08;Quality Efficiency Conference&#xff09;质量效能大会在上海正式开幕&#xff01;本次大会以"数生智慧&#xff1a;高质量发展新引擎"为主题&#xff0c;深入探讨如何借助数字化和智能化技术推动软件质量的发展&#xff0c;为高质量经济发展提供…

【TES720D-KIT】青翼科技支持双网口的全国产化四核CPU+FPGA处理器开发套件

TES720D-KIT是专门针对我司TES710D&#xff08;基于复旦微FMQL10S400的全国产化ARM核心板&#xff09;的一套开发套件&#xff0c;它包含1个TES720D核心板&#xff0c;加上一个TES720D-EXT扩展底板。 FMQL20S400是复旦微电子研制的全可编程融合芯片&#xff0c;在单芯片内集成…

第八章 排序 七、堆排序

目录 一、堆的概念 1、大根堆 2、小根堆 二、建立大根堆 1、举个例子&#xff0c;我们要让一个序列变换成为一个大根堆 2、我们把序列看成一棵完全二叉树&#xff0c;而完全二叉树有以下特性&#xff1a; 3、在此序列中&#xff0c;由于是从1开始的序列&#xff0c;所以分…

海外网红营销:赢得年轻人的心,打破传统的秘密武器

随着数字时代的崛起&#xff0c;社交媒体已经成为了年轻人生活的一部分。年轻人在社媒平台上创造和分享内容&#xff0c;构建着他们的社交圈子&#xff0c;也塑造着全球的文化和趋势。对于企业来说&#xff0c;赢得年轻人的心已经成为了一项关键任务&#xff0c;而海外网红营销…

linux环境下 查看 进程内存占用情况

新版本 -o %MEM 按内存排序 top -o %MEM -b -n 1 | grep java | awk {print "PID: "$1" \t MEM: "$6" \t %CPU: "$9"% \t %MEM: "$10"%"} 通过指令找到内存消耗量最大的几个进程 查看内存消耗情况 top -b -n 1 | grep jav…

Linux从时间服务器同步时间

一、基本设定 自己的时间服务器&#xff1a;111.11.11.111 二、操作 查看当前时间命令&#xff1a;date&#xff0c;发现时间不一致。 同步命令&#xff1a;/usr/sbin/ntpdate 111.11.11.111 然后等待同步完成即可。 如果同步命令不可用&#xff0c;需要先安装Ntp服务&…

使用运放产生各种波形

目录复制 文章目录 RC正弦振荡电路文氏电桥振荡电路移项式正弦波振荡电路 集成函数发生器运算放大器驱动电容性负载峰值检波多通道运放未使用的运放接法 RC正弦振荡电路 文氏电桥振荡电路 这个振荡器起振条件RF > 2R1,起振后又希望RF 2R1产生矛盾怎么办&#xff1f; 将RF换…

LeetCode 1251. 平均售价

题目链接&#xff1a;1251. 平均售价 题目描述 表&#xff1a;Prices Column NameTypeproduct_idintstart_datedateend_datedatepriceint (product_id&#xff0c;start_date&#xff0c;end_date) 是 prices 表的主键&#xff08;具有唯一值的列的组合&#xff09;。 price…

开发者指南:如何集成一对一直播美颜SDK到你的应用中

本文将为开发者们提供一个详细的指南&#xff0c;教你如何将一对一直播美颜SDK集成到你的应用中&#xff0c;以提供更具吸引力的直播体验。 -为什么选择一对一直播美颜SDK&#xff1f; 在开始之前&#xff0c;让我们先明确一下为什么选择一对一直播美颜SDK是一个明智的决定。…