博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
面向对象:抽象类,继承的实现原理,封装
阅读量:4924 次
发布时间:2019-06-11

本文共 5104 字,大约阅读时间需要 17 分钟。

抽象类:

本身不能被实例化,也不应该被实例化,他的作用就是定义标准,不用具体的实现

继承的实现原理:

注:新式类可以使用print(<class_name>.mro())来查询,经典类无法使用

如下继承关系

根据上图代码示例:class A:    def test(self):        print('from A')    passclass B(A):    def test(self):        print('from B')    passclass C:    def test(self):        print('from C')    passclass D:    def test(self):        print('from D')    passclass E(B,C,D):    def test(self):        print('from E')    passe = E()e.test()执行结果:默认这样执行,会显示"from E" ,因为调用一个方法会,先从自己的类中查询,下面我们依次注释掉下列类的test:把E类的test注释掉:结果显示"from B" ,把B类的test注释掉:结果显示"from A" ,把A类的test注释掉:结果显示"from C" ,把C类的test注释掉:结果显示"from D" ,把D类的test注释掉:结果显示"'E' object has no attribute 'test'"根据上面的结果过程:在Python3中,当继承多个父类时且父类没有共同的父类时,这时属性的查询顺序是(深度优先)上面的属性查询顺序总结:E-->B-->A-->C-->D这个可能不是很有说服力,那么我们在新建一个F类,让C类继承F类,这时属性的查询顺序如下(仅列出结果):属性查询顺序:E-->B-->A-->C-->F-->D

  

如果继承多个附类且父类有共同的父类时:

根据上图代码示例:class A:    def test(self):        print('from A')    passclass B(A):    def test(self):        print('from B')    passclass C(A):    def test(self):        print('from C')    passclass D:    def test(self):        print('from D')    passclass E(B,C,D):    def test(self):        print('from E')    passe = E()e.test()执行结果:默认执行:显示"from E"把E类的test注释掉:结果显示"from B"把B类的test注释掉:结果显示"from C"把C类的test注释掉:结果显示"from A"把A类的test注释掉:结果显示"from D"把D类的test注释掉:结果显示"'E' object has no attribute 'test'"根据上面测试的结果:得出结论在Python3中,当继承多个父类且父类还有共同的父类时,这时属性查找是(广度优先)上面的属性查找顺序总结:E-->B-->C-->A-->D

  

注:在Python2中因为分新式类和经典类的区别,所以跟Python3有些许不同。

如下图在Python2中:

  新式类:同Python3中一样,是广度优先。所以属性查找顺序是:E-->B-->C-->A-->D

  经典类:和新式类恰恰相反,是深度优先。所以属性查找顺序是:E-->B-->A-->C-->D

子类调用父类的方法:

super():内置函数,使用绑定方法调用父类的方法。(仅支持新式类)

注:在Python2中需要写成:super(S1,self).__init__(name,age)   #S1 为子类的名字。

class Parent:    def __init__(self,name,age):        self.name = name        self.age = ageclass D:    def walk(self):        return ('from D')class S1(Parent,D):    def __init__(self,name,age,job,school):        super().__init__(name,age)   #因为使用绑定方法调用父类的方法,所以不需要传递self        self.job = job        self.school = school        super().walk()t = S1('egon',73,'teach','oldboy')print(t.name,t.age,t.walk())执行结果:D:\Python\Python36-32\python.exe E:/Python/DAY-20/day20.pyegon 73 from DProcess finished with exit code 0

  

封装:

  注:Python中没有真正的隐藏,仅仅是语法上做了些操作。

  方法:

    在想要封装的变量或者函数名前加上"__"两个下划线,就可以。

    加上两个下划线之后,只有在类的定义阶段或者对象的定义阶段(实例化)发生。且在类的外部无法直接调用,但是在类的内部可以直接调用(在定义时全部变形了)

    封装其实就是变形。

正常的状态:(注意观察下列红色标识)class A:    def foo(self):        print('from A foo')        self.bar()    def bar(self):        print('from A bar')class B(A):    def bar(self):        print('from B bar')b = B()print(A.__dict__)  b.foo()    #正常状态调用 .foo(),因为A是B的父类,B类中没有foo所以向上查找,在A中找到并执行,foo有个self.bar,self指的对象所以可以认为是在执行b.bar() 又搜寻一次父类,在B中找到,所以结果显示from B bar 执行结果:D:\Python\Python36-32\python.exe E:/Python/DAY-20/day20.py{'__module__': '__main__', 'foo': 
, 'bar':
, '__dict__':
, '__weakref__':
, '__doc__': None}from A foofrom B barProcess finished with exit code 0隐藏变形:class A: def foo(self): print('from A foo') self.__bar() #做了隐藏,这时在执行找到就不是bar了,而是 _A__bar,下面的结果能看出来名字被变形了 def __bar(self): #这里等于 _A__bar(self) 所以最后显示 from A bar print('from A bar')class B(A): def bar(self): print('from B bar')b = B()print(A.__dict__)b.foo()执行结果:D:\Python\Python36-32\python.exe E:/Python/DAY-20/day20.py{'__module__': '__main__', 'foo':
, '_A__bar':
, '__dict__':
, '__weakref__':
, '__doc__': None}from A foofrom A barProcess finished with exit code 0

  

一个封装的例子

class User:    def __init__(self,name,age,sex):   #这里能看到隐藏了所有的用户信息        self.__name = name        self.__age = age        self.__sex =sex    def modify_name(self,val):   #定义更改用户名的接口        if not isinstance(val,str):   #判断是否是字符串            raise TypeError('must be str')   #如果不是字符串则主动抛出异常        self.__name = val   #如果是字符串则执行这条,重新赋值    def dis_info(self):   #显示用户信息        print('''        Name:%s        Age:%s        Sex:%s        '''%(self.__name,self.__age,self.__sex))t = User('laochai',73,'male')   #传入参数 用户名为 laochait.modify_name('abc')   #更改用户名 abct.dis_info()   #打印信息执行结果:D:\Python\Python36-32\python.exe E:/Python/DAY-20/day20.py        Name:abc        Age:73        Sex:male        Process finished with exit code 0

   Property:内置函数,一个装饰器,功能是自动执行函数,可以在封装中起到去括号的目的,让用户不知道自己被套路了。

class User:    def __init__(self,name,age,sex):        self.__name = name        self.__age = age        self.__sex =sex    @property    #加上property装饰name    def name(self):        print(self.__name)    @name.setter  #调用 .setter方法    def name(self,val):        self.__name = val   #修改用户名    @property  #调用property装饰    def dis_info(self):        print('''        Name:%s        Age:%s        Sex:%s        '''%(self.__name,self.__age,self.__sex))t = User('egon',18,'male')t.name = 'abc'   #直接修改用户名t.dis_info   #查看信息时没有加()执行执行结果:D:\Python\Python36-32\python.exe E:/Python/DAY-20/day20.py        Name:abc        Age:18        Sex:male        Process finished with exit code 0

  

转载于:https://www.cnblogs.com/yuxiang-qiwa/p/7894337.html

你可能感兴趣的文章
调查表与调查结果分析
查看>>
Windows系统下安装MySQL详细教程(命令安装法)
查看>>
PHP实用小程序(六)
查看>>
PDFsharp Samples
查看>>
django-cms 代码研究(八)app hooks
查看>>
peewee Model.get的复杂查询
查看>>
IE浏览器兼容性设置的一些问题
查看>>
SQL Server复制入门(二)----复制的几种模式
查看>>
javascript 简单认识
查看>>
tomcat 系统架构与设计模式 第二部分 设计模式 转
查看>>
scanf中的%[^\n]%*c格式
查看>>
启动Eclipse报Initializing Java Tooling错误解决方法
查看>>
用jquery来实现类似“网易新闻”横向标题滑动的移动端页面
查看>>
(原)基于物品的协同过滤ItemCF的mapreduce实现
查看>>
CSS可以和不可以继承的属性
查看>>
eclipse每次当我按ctrl+鼠标点击代码,自动关闭,产生原因及解决办法!!
查看>>
hbase
查看>>
用PHP将Unicode 转化为UTF-8
查看>>
HDOJ1002 A+B Problem II
查看>>
ADB server didn't ACK(adb不能开启
查看>>