顶顶顶顶顶顶顶顶顶顶顶顶

在这里插入图片描述

欢迎关注博主 Mindtechnist 或加入【智能科技社区】一起学习和分享Linux、C、C++、Python、Matlab,机器人运动控制、多机器人协作,智能优化算法,滤波估计、多传感器信息融合,机器学习,人工智能等相关领域的知识和技术。关注公粽号 《机器和智能》 回复关键词 “python项目实战” 即可获取美哆商城视频资源!


博主介绍:
CSDN博客专家,CSDN优质创作者,CSDN实力新星,CSDN内容合伙人;
阿里云社区专家博主;
华为云社区云享专家;
51CTO社区入驻博主,掘金社区入驻博主,支付宝社区入驻博主,博客园博主。


python面向对象 —— 继承、多态、封装

    • python中的继承
    • 在python中模仿Java的Interface
    • 抽象类 – 接口继承
    • 继承顺序
    • python中的继承原理(python3)
    • 子类中调用父类方法 – super方法
    • python中的多态
    • python中的封装


专栏:《python从入门到实战》


python中的继承

class Parent1:passclass Parent2:passclass sub(Parent1): #单继承passclass sub2(Parent1, Parent2): #多继承pass

子类继承了父类所有的属性,如果子类属性和父类属性同名,那么在使用的时候,子类会使用自己的属性,因为搜索的顺序是先找自己的,自己没有再去找父类的,如果自己有就用自己的。注意,子类没有覆盖父类的属性,父类的属性还是父类的,子不过子类使用同名属性的时候会先找到自己的属性。如果用父类去使用这个属性,那么父类得到的是自己的值。比如父类有一个属性flag = 10,子类也定义了一个flag = 11,那么son.flag = 11,father.flag = 10,各是各的,不存在值被覆盖这种情况。

继承的两层含义:

  • 继承基类的方法,并且做出自己的改变或者扩展(代码重用)。子类与父类耦合,应尽量避免使用。
  • 声明某个子列兼容于某基类,定义一个接口类,子类继承接口类并实现接口类中定义的方法。(继承的真正应用)

实际使用中,继承的第一重含义往往会使得子类与基类出现强耦合,实际意义不大甚至有害。继承的第二层含义非常重要,也被称为接口继承。接口继承实质上是要求做出一个良好的抽象,这个抽象规定了一个兼容接口,使得外部调用者不需要关心具体细节,可以一视同仁的处理实现了特定接口的所有对象,即归一化。归一化使得高层的外部使用者可以不加区分的处理所有接口兼容的对象集合,就好像Linux中一切皆文件(泛文件概念),所有东西都作为文件处理,不必关心它具体是内存、磁盘还是网络或者屏幕(但是底层设计者需要区分字符设备、块设备等等),在python中,一切皆对象。

继承与组合的区别:

  • 继承建立了基类与派生类之间的关系,它是一种‘是’的关系;
  • 组合建立了类与组合类之间的关系,它是一种‘有’的关系;

在python中模仿Java的Interface

class Interface:#定义接口Interface类来模仿接口的概念,python中压根就没有interface关键字来定义一个接口。def read(self): #定接口函数readpassdef write(self): #定义接口函数writepassclass Txt(Interface): #文本,具体实现read和writedef read(self):print('文本数据的读取方法')def write(self):print('文本数据的读取方法')class Sata(Interface): #磁盘,具体实现read和writedef read(self):print('硬盘数据的读取方法')def write(self):print('硬盘数据的读取方法')class Process(Interface):def read(self):print('进程数据的读取方法')def write(self):print('进程数据的读取方法')

抽象类 – 接口继承

抽象类是一个特殊的类,它的特殊之处在于只能被继承,不能被实例化,且子类必须实现抽象方法。
抽象类的本质还是类,指的是一组类的相似性,包括数据属性(如all_type)和函数属性(如read、write),而接口只强调函数属性的相似性。
抽象类是一个介于类和接口直接的一个概念,同时具备类和接口的部分特性,可以用来实现归一化设计 。

#_*_coding:utf-8_*_
__author__ = 'Linhaifeng'
#一切皆文件
import abc #利用abc模块实现抽象类class All_file(metaclass=abc.ABCMeta):all_type='file'@abc.abstractmethod #定义抽象方法,无需实现功能def read(self):'子类必须定义读功能'pass@abc.abstractmethod #定义抽象方法,无需实现功能def write(self):'子类必须定义写功能'pass# class Txt(All_file):
#     pass
#
# t1=Txt() #报错,子类没有定义抽象方法class Txt(All_file): #子类继承抽象类,但是必须定义read和write方法def read(self):print('文本数据的读取方法')def write(self):print('文本数据的读取方法')class Sata(All_file): #子类继承抽象类,但是必须定义read和write方法def read(self):print('硬盘数据的读取方法')def write(self):print('硬盘数据的读取方法')class Process(All_file): #子类继承抽象类,但是必须定义read和write方法def read(self):print('进程数据的读取方法')def write(self):print('进程数据的读取方法')wenbenwenjian=Txt()yingpanwenjian=Sata()jinchengwenjian=Process()#这样大家都是被归一化了,也就是一切皆文件的思想
wenbenwenjian.read()
yingpanwenjian.write()
jinchengwenjian.read()print(wenbenwenjian.all_type)
print(yingpanwenjian.all_type)
print(jinchengwenjian.all_type)

继承顺序

python中的类可以继承多个类,Java和C#只能继承一个类。如果python中的类继承了多个类,那么寻找方法有两种,广度优先和深度优先。
在这里插入图片描述
如果类是经典类,在多继承的情况下,会按照深度优先的方式查找。
在这里插入图片描述

如果类是新式类,在多继承的情况下,会按照广度优先的方式查找。

在这里插入图片描述

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):def test(self):print('from D')class E(C):def test(self):print('from E')class F(D,E):# def test(self): #通过一层一层的注释,来打印查找顺序#     print('from F')pass
f1=F()
f1.test()
print(F.__mro__) #只有新式才有这个属性可以查看线性列表,经典类没有这个属性
#也就是说 python2中经典类没有这个方法,新式类有
#新式类继承顺序:F->D->B->E->C->A
#经典类继承顺序:F->D->B->A->E->C
#python3中统一都是新式类
#pyhon2中才分新式类与经典类

python中的继承原理(python3)

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

>>> F.mro() #等同于F.__mro__
[<class '__main__.F'>, <class '__main__.D'>, <class '__main__.B'>, <class '__main__.E'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>] 
#新式类都继承于object类 – python3都是新式类

为了实现继承,python会在MRO列表上从左到右开始查找基类,直到找到第一个匹配这个属性的类为止。
而这个MRO列表的构造是通过一个C3线性化算法来实现的。我们不去深究这个算法的数学原理,它实际上就是合并所有父类的MRO列表并遵循如下三条准则:
1.子类会先于父类被检查
2.多个父类会根据它们在列表中的顺序被检查
3.如果对下一个类存在两个合法的选择,选择第一个父类
新式类与经典类:新式类都继承了object类,经典类没有继承object。只有python2区分新式类与经典类,python3不区分新式类与经典类。

子类中调用父类方法 – super方法

显示调用:父类名.父类方法()

#_*_coding:utf-8_*_
__author__ = 'Linhaifeng'class Vehicle: #定义交通工具类Country='China'def __init__(self,name,speed,load,power):self.name=nameself.speed=speedself.load=loadself.power=powerdef run(self):print('开动啦...')class Subway(Vehicle): #地铁def __init__(self,name,speed,load,power,line):Vehicle.__init__(self,name,speed,load,power)#只有实例化和对象调类方法的时候,self才会自动传值,这里需要手动传self.line=linedef run(self):print('地铁%s号线欢迎您' %self.line)Vehicle.run(self)line13=Subway('中国地铁','180m/s','1000人/箱','电',13)
line13.run()

super()方法

class Vehicle: #定义交通工具类Country='China'def __init__(self,name,speed,load,power):self.name=nameself.speed=speedself.load=loadself.power=powerdef run(self):print('开动啦...')class Subway(Vehicle): #地铁def __init__(self,name,speed,load,power,line):#super(Subway,self) 就相当于实例本身 在python3中super()等同于super(Subway,self)super().__init__(name,speed,load,power)self.line=linedef run(self):print('地铁%s号线欢迎您' %self.line)super(Subway,self).run()class Mobike(Vehicle):#摩拜单车passline13=Subway('中国地铁','180m/s','1000人/箱','电',13)
line13.run()

super.父类方法() – 无需写父类名,无需传参self
即使没有直接继承关系,super仍然会按照mro继续往后查找

#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):passc=C()
c.test() #打印结果:from Bprint(C.mro())
#[<class '__main__.C'>, <class '__main__.A'>, <class '__main__.B'>, <class 'object'>]

指名道姓的显式调用与super有什么区别

#指名道姓
class A:def __init__(self):print('A的构造方法')
class B(A):def __init__(self):print('B的构造方法')A.__init__(self)class C(A):def __init__(self):print('C的构造方法')A.__init__(self)class D(B,C):def __init__(self):print('D的构造方法')B.__init__(self)C.__init__(self)pass
f1=D() #A.__init__被重复调用
'''
D的构造方法
B的构造方法
A的构造方法
C的构造方法
A的构造方法
'''#使用super()
class A:def __init__(self):print('A的构造方法')
class B(A):def __init__(self):print('B的构造方法')super(B,self).__init__()class C(A):def __init__(self):print('C的构造方法')super(C,self).__init__()class D(B,C):def __init__(self):print('D的构造方法')super(D,self).__init__()f1=D() #super()会基于mro列表,往后找
'''
D的构造方法
B的构造方法
C的构造方法
A的构造方法
'''

当你使用super()函数时,Python会在MRO列表上继续搜索下一个类。只要每个重定义的方法统一使用super()并只调用它一次,那么控制流最终会遍历完整个MRO列表,每个方法也只会被调用一次(注意注意注意:使用super调用的所有属性,都是从MRO列表当前的位置往后找,千万不要通过看代码去找继承关系,一定要看MRO列表)

#A没有继承B,但是A内super会基于C.mro()继续往后找
class A:def test(self):print('A---->test')super().aaa()
class B:def test(self):print('B---->test')def aaa(self):print('B---->aaa')class C(A,B):def aaa(self):print('C----->aaa')c=C()
c.test() #打印结果:
'''
A---->test
B---->aaa
'''print(C.mro()) # C作为方法调用(即c.test())的发起者,方法调用过程中涉及的属性查找都参考C.mro()。父子关系按照mro列表为准,千万不要从代码层面看父子。例如
# c.test(),发起者C.mro()列表如下,从列表中可以看出,B类就是A类他爹,而代码层面二者并无继承关系
#[<class '__main__.C'>, <class '__main__.A'>, <class '__main__.B'>, <class 'object'>]

python中的多态

len([1, 2, 3])
len(‘hello’)
len((1, 3))
# ---- 这就是多态
l = [1, 3, 4]
len(l)  l.__line__()
import abc
class File(metaclass=abc.ABCMeta): #同一类事物:文件@abc.abstractmethoddef click(self):passclass Text(File): #文件的形态之一:文本文件def click(self):print('open file')class ExeFile(File): #文件的形态之二:可执行文件def click(self):print('execute file')
peo=People()
dog=Dog()
pig=Pig()#peo、dog、pig都是动物,只要是动物肯定有talk方法
#于是我们可以不用考虑它们三者的具体是什么类型,而直接使用
peo.talk()
dog.talk()
pig.talk()#更进一步,我们可以定义一个统一的接口来使用
def func(obj):
obj.talk()
"""
这样就模仿了一个类似于len的多态
我们使用len的时候,传入一个对象len(obj),实际上就相当于调用obj的__len__方法,这里也一样,func(obj),就相当于调用obj的talk方法,这就是多态。
"""
  • 多态动态绑定
  • 多态性:静态多态性、动态多态性
  • 多态是体现在运行时的。

python中的封装

python中约定,单下划线_开头的是私有的,不应该在外部使用,但是实际上这只是一种约定,在外部调用也是可以的,python并没有限制真正的私有。

在python中用双下划线开头的方式将属性隐藏起来(设置成私有的)

#其实这仅仅这是一种变形操作且仅仅只在类定义阶段发生变形
#类中所有双下划线开头的名称如__x都会在类定义时自动变形成:_类名__x的形式:class A:__N=0 #类的数据属性就应该是共享的,但是语法上是可以把类的数据属性设置成私有的如__N,会变形为_A__Ndef __init__(self):self.__X=10 #变形为self._A__Xdef __foo(self): #变形为_A__fooprint('from A')def bar(self):self.__foo() #只有在类内部才可以通过__foo的形式访问到.#A.__N #err 访问不到,因为__N已经被改名了,改成了_A__N
#A._A__N #是可以访问到的
#这种,在外部是无法通过__x这个名字访问到。

这种机制也并没有真正意义上限制我们从外部直接访问属性,知道了类名和属性名就可以拼出名字:__类名__属性,然后就可以访问了,如a._A__N,即这种操作并不是严格意义上的限制外部访问,仅仅只是一种语法意义上的变形,主要用来限制外部的直接访问。变形的过程只在类的定义时发生一次,在定义后的赋值操作,不会变形。在继承中,父类如果不想让子类覆盖自己的方法,可以将方法定义为私有的。
封装的真谛在于明确地区分内外,封装的属性可以直接在内部使用,而不能被外部直接使用,然而定义属性的目的终归是要用,外部要想用类隐藏的属性,需要我们为其开辟接口(对外提供访问内部私有属性的接口),让外部能够间接地用到我们隐藏起来的属性,那这么做的意义何在???
1:封装数据:将数据隐藏起来这不是目的。隐藏起来然后对外提供操作该数据的接口,然后我们可以在接口附加上对该数据操作的限制,以此完成对数据属性操作的严格控制。

class Teacher:def __init__(self,name,age):# self.__name=name# self.__age=ageself.set_info(name,age)def tell_info(self):print('姓名:%s,年龄:%s' %(self.__name,self.__age))def set_info(self,name,age):if not isinstance(name,str):raise TypeError('姓名必须是字符串类型')if not isinstance(age,int):raise TypeError('年龄必须是整型')self.__name=nameself.__age=aget=Teacher('egon',18)
t.tell_info()t.set_info('egon',19)
t.tell_info()

2:封装方法:目的是隔离复杂度
封装方法举例:

  1. 电视机本身是一个黑盒子,隐藏了所有细节,但是一定会对外提供了一堆按钮,这些按钮也正是接口的概念,所以说,封装并不是单纯意义的隐藏!!!
  2. 快门就是傻瓜相机为傻瓜们提供的方法,该方法将内部复杂的照相功能都隐藏起来了
    提示:在编程语言里,对外提供的接口(接口可理解为了一个入口),可以是函数,称为接口函数,这与接口的概念还不一样,接口代表一组接口函数的集合体。
#取款是功能,而这个功能有很多功能组成:插卡、密码认证、输入金额、打印账单、取钱
#对使用者来说,只需要知道取款这个功能即可,其余功能我们都可以隐藏起来,很明显这么做
#隔离了复杂度,同时也提升了安全性class ATM:def __card(self):print('插卡')def __auth(self):print('用户认证')def __input(self):print('输入取款金额')def __print_bill(self):print('打印账单')def __take_money(self):print('取款')def withdraw(self):self.__card()self.__auth()self.__input()self.__print_bill()self.__take_money()a=ATM()
a.withdraw()

python并不会真的阻止你访问私有的属性,模块也遵循这种约定,如果模块名以单下划线开头,那么from module import *时不能被导入,但是你from module import _private_module依然是可以导入的。其实很多时候你去调用一个模块的功能时会遇到单下划线开头的(socket._socket, sys._home, sys._clear_type_cache)这些都是私有的,原则上是供内部调用的,作为外部的你,也是可以用的, python要想与其他编程语言一样,严格控制属性的访问权限,只能借助内置方法如__getattr__。


在这里插入图片描述
在这里插入图片描述


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

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

相关文章

【电子通识】为什么用双绞线?双绞线抗干扰的原理是什么?

使用双绞线最大的理由是抗干扰。不仅可以防止别人干扰,也可以防止自己干扰别人。这与EMC中的EMS和EMI相对应(参考【EMC专题】电磁兼容--基本概念)。 双绞线是由一对带有绝缘层的铜线(绝缘层使两根线中的金属导体不会因为互碰而导致短路)以螺旋的方式缠绕在一起所构成的。通…

ElementUI从unpkg.com完整下载到本地的方法 - 解决unpkg.com不稳定的问题 - 自建镜像站 - 不想打包只想cdn一下

方法 方法1&#xff09;随便弄个文件夹&#xff0c;根据官网npm方法下载包&#xff0c;提取即可 npm i element-ui -S cd /node_modules/element-ui/ ls src 安装npm方法&#xff1a;https://nodejs.org/en 方法2&#xff09;不推荐 - 在github中搜索对应的库zip包&#xff0…

【网络原理】HTTP 协议的基本格式和 fiddler 抓包工具的用法

系列文章目录 【网络通信基础】网络中的常见基本概念 【网络编程】网络编程中的基本概念及Java实现UDP、TCP客户端服务器程序&#xff08;万字博文&#xff09; 【网络原理】UDP协议的报文结构 及 校验和字段的错误检测机制&#xff08;CRC算法、MD5算法&#xff09; 【网络…

PG实例连接访问控制

实例访问控制可以控制来自于不同主机&#xff0c;不同用户是否允许访问指定的数据库&#xff0c;以及验证方式。 与oracle中的连接管理器的功能相同&#xff0c;之前有写过一篇oracleCMAN连接管理器的配置实操&#xff1a; 配置oracle连接管理器&#xff08;cman&#xff09;…

深度学习每周学习总结P7(咖啡豆识别)

&#x1f368; 本文为&#x1f517;365天深度学习训练营 中的学习记录博客&#x1f356; 原作者&#xff1a;K同学啊 | 接辅导、项目定制 –来自百度网盘超级会员V5的分享 数据链接 提取码&#xff1a;7zt2 –来自百度网盘超级会员V5的分享 目录 0. 总结1. 数据导入及处理部分…

文章解读与仿真程序复现思路——电力自动化设备EI\CSCD\北大核心《电-氢-混氢天然气耦合的城市综合能源系统低碳优化调度》

本专栏栏目提供文章与程序复现思路&#xff0c;具体已有的论文与论文源程序可翻阅本博主免费的专栏栏目《论文与完整程序》 论文与完整源程序_电网论文源程序的博客-CSDN博客https://blog.csdn.net/liang674027206/category_12531414.html 电网论文源程序-CSDN博客电网论文源…

Java | Leetcode Java题解之第68题文本左右对齐

题目&#xff1a; 题解&#xff1a; class Solution {private String line(List<String> list,int maxWidth,int totalLength,boolean isLast){StringBuilder sb new StringBuilder();sb.append(list.get(0));if(list.size() 1){String ap " ".repeat(maxW…

二维数组的鞍点(C语言)

一、鞍点解释&#xff1b; 鞍点就是该位置上的元素在该行上最大、在该列上最小&#xff1b; 二、N-S流程图&#xff1b; 三、运行结果&#xff1b; 四、源代码&#xff1b; # define _CRT_SECURE_NO_WARNINGS # include <stdio.h>int main() {//初始化变量值&#xff…

定制开发AI名片商城AI导购系统:引领营销自动化的新时代

在数字营销日新月异的今天&#xff0c;一个革命性的工具——定制开发AI名片商城AI导购系统&#xff0c;正逐渐崭露头角&#xff0c;成为企业私域运营中的得力助手。它不仅仅是一个营销工具&#xff0c;更是一个拥有强大营销自动化能力和先进算法技术的在线助理&#xff0c;为企…

【neteq】tgcall的调用

G:\CDN\P2P-DEV\Libraries\tg_owt\src\call\call.cc基本是按照原生webrtc的来的:G:\CDN\P2P-DEV\tdesktop-offical\Telegram\ThirdParty\tgcalls\tgcalls\group\GroupInstanceCustomImpl.cpptg对neteq的使用 worker 线程创建call Call的config需要neteqfactory Call::CreateAu…

[1702]java旅游资源网上填报系统Myeclipse开发mysql数据库web结构java编程计算机网页项目

一、源码特点 java旅游资源网上填报系统是一套完善的java web信息管理系统&#xff0c;对理解JSP java编程开发语言有帮助&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要采用B/S模式开发。开发环境为 TOMCAT7.0,Myeclipse8.5开发&#xff0c;数据库为Mysql…

模式识别作业:颜色算子的三种阈值分割算法

一、引言&#xff1a; 在图像处理中&#xff0c;我们往往需要提取图像的一些关键信息&#xff0c;比如本篇文章的内容——提取颜色&#xff0c;然而当我们需要提取某一种颜色时&#xff0c;无论图像余下的部分如何“丰富多彩”&#xff0c;他们都不再重要&#xff0c;需要被忽…

如何使用SSH密钥克隆仓库

1.创建SSH Key 在用户目录下查看有没有.ssh目录。如果有且该.ssh目录下有id_rsa&#xff08;私钥&#xff09;&#xff0c;和id_rse_pub(公钥)这俩文件&#xff0c;那么这一步就可以跳过。否则使用以下指令创建SSH Key ssh-keygen -t rsa -C "xxxqq.com" "xx…

8.k8s中网络资源service

目录 一、service资源概述 二、service资源类型 1.ClusterIP类型 2.service的nodeport类型 3.service的loadbalancer类型&#xff08;了解即可&#xff09; 4.service的externalname类型&#xff08;了解即可&#xff09; 三、nodeport的端口范围设置和svc的endpoint列表 1.修…

AJAX概述和基本使用

01 【AJAX概述和基本使用】 1.AJAX简介 AJAX 全称为Asynchronous JavaScript And XML&#xff0c;就是异步的JS 和XML 通过AJAX 可以在浏览器中向服务器发送异步请求&#xff0c;最大的优势&#xff1a;无刷新获取数据 AJAX 不是新的编程语言&#xff0c;而是一种将现有的标准…

刷代码随想录有感(53):合并二叉树

题干&#xff1a; 代码&#xff08;递归实现&#xff09;&#xff1a; TreeNode* mergeTrees(TreeNode* root1, TreeNode* root2) {//前序好理解&#xff0c;直接将树覆盖到另一个上面if(root1 NULL)return root2;//当前遍历节点为空的话就让另一个的值覆盖过来if(root2 NUL…

对命令模式的理解

目录 一、场景1、文本编辑器并不是一个好的例子&#xff0c;设备控制器才是2、设备控制器的demo 二、不用命令模式1、代码2、问题 三、使用命令模式1、代码2、当需求变化时2.1 新增代码2.2 优点 四、进一步思考1、省略对Command的建模可以吗&#xff1f;2、命令模式的价值 一、…

GDPU unity游戏开发 碰撞器与触发器

砰砰叫&#xff0c;谁动了她的奶酪让你的小鹿乱撞了。基于此&#xff0c;亦即碰撞与触发的过程。 碰撞器与触发器的区别 通俗点讲&#xff0c;碰撞器检测碰撞&#xff0c;触发器检测触发&#xff0c;讲了跟没讲似的。碰撞器是用来检测碰撞事件的&#xff0c;在unity中&#xff…

蓝桥杯练习系统(算法训练)ALGO-949 勇士和地雷阵

资源限制 内存限制&#xff1a;256.0MB C/C时间限制&#xff1a;1.0s Java时间限制&#xff1a;3.0s Python时间限制&#xff1a;5.0s 问题描述 勇士们不小心进入了敌人的地雷阵&#xff08;用n行n列的矩阵表示&#xff0c;*表示某个位置埋有地雷&#xff0c;-表示某个…

yolov5-pytorch-Ultralytics训练+预测+报错处理记录

一、前言 玩一段时间大模型&#xff0c;也该回归一下图像识别。本项目用于记录使用基于Ultralytics的yolov5进行目标检测测试。为什么用Ultralytics呢&#xff1f;答案有3 1、其良好的生态&#xff0c;方便我们部署到其它语言和设备上。因此本次测试结论&#xff1a;大坑没有&…