第二十五天 PYTHON学习

【今日学习】

一、继承补充

1.继承的实现原理

python到底是如何实现继承的,对于你定义的每一个类,python会计算出一个方法解析顺序(MRO)列表,这个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):
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__) #只有新式才有这个属性可以查看线性列表,经典类没有这个属性

#新式类继承顺序:F->D->B->E->C->A
#经典类继承顺序:F->D->B->A->E->C
#python3中统一都是新式类
#pyhon2中才分新式类与经典类

继承顺序

只有新式类才mro,才能查看到这个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'>]

2.子类继承父类的方法
子类调用父类有两种方法:
一是指名道姓调用,这种方法不需要继承也能实现
二是通过super(类名,self).__init__()实现,注意super里面的类名可以不是这个被触发的类,可以写是被继承的类,表明跳过这个被继承类,但不意味着跳过这个被继承类的父类


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

3.组合与继承的关系
软件代码重用的重要解决方法除了继承外,还有一个方法叫组合,组合是在一个类中以另外一个类的对象作为数据属性,称为类的组合

组合与继承都是有效地利用已有类的资源的重要方式。但是二者的概念和使用场景皆不同:

1.继承的方式

通过继承建立了派生类与基类之间的关系,它是一种'是'的关系,比如白马是马,人是动物。

当类之间有很多相同的功能,提取这些共同的功能做成基类,用继承比较好,比如老师是人,学生是人

2.组合的方式

用组合的方式建立了类与组合的类之间的关系,它是一种‘有’的关系,比如教授有生日,教授教python和linux课程,教授有学生s1、s2、s3...,当类之间有显著不同,并且较小的类是较大的类所需要的组件时,用组合比较好。

二、面向对象之封装

1.什么是封装:

装指的是把属性装进一个容器
封指的是隐藏的意思,但是这种隐藏是对外不对内的

2.为何要封装:

封装数据属性的目的:将数据属性封装起来,类外部的使用就无法直接操作该数据属性了
需要类内部开一个接口给使用者,类的设计者可以在接口之上附加任意逻辑,从而严格
控制使用者对属性的操作
封装函数属性的目的:隔离复杂度

3.如何封装:

    只需要在属性前加上__开头,该属性就会被隐藏起来,该隐藏具备的特点:

1. 只是一种语法意义上的变形,即__开头的属性会在检测语法时发生变形_类名__属性名
2. 这种隐藏式对外不对内的,因为在类内部检测语法时所有的代码统一都发生的变形
3. 这种变形只在检测语法时发生一次,在类定义之后新增的__开头的属性并不会发生变形
4. 如果父类不想让子类覆盖自己的属性,可以在属性前加__开头

4.封装的意义
封装的真谛是区分内外,让外部不能通过正常方式使用,但内部可以通过正常方式直接使用。封装的目的不是不再使用封装内的数据,还是需要对封装内的数据属性进行增删改查的。
那怎么做到,通过在封装内进行函数操作实现数据的增删改查,然后在外部调用函数实现,同时也可以为封装后的数据设置增删改查的条件限制

python不会真的阻止用户直接操作被封装的部分,只不过有些不常修改的部分,封装起开,减少被随意调用。

5.通过property特性这个装饰器,可以实现 在对象调用数据时,让使用者无法察觉是通过直接调用还是通过函数调用,这样既达到查看数据目的,又可以防止用户通过正常方式修改的目的,当然如果想实现
正常方式修改,仍然可以在类内再定义一个修改函数,但在此之前必须让property定义需要修改的部分。才可以实现正常途径的修改。

6.封装与拓展性
封装在于明确区分内外,使得类实现者可以修改封装内的东西而不影响外部调用者的代码;而外部使用用者只知道一个接口(函数),只要接口(函数)名、参数不变,
使用者的代码永远无需改变。这就提供一个良好的合作基础——或者说,只要接口这个基础约定不变,则代码改变不足为虑。


三、多态与多态性
多态指的是一类事物有多种形态。
多态性指的是可以在不用考虑对象具体类型的前提下而直接使用对象下的方法

  鸭子类型

逗比时刻:

  Python崇尚鸭子类型,即‘如果看起来像、叫声像而且走起路来像鸭子,那么它就是鸭子’

python程序员通常根据这种行为来编写程序。例如,如果想编写现有对象的自定义版本,可以继承该对象

也可以创建一个外观和行为像,但与它无任何关系的全新对象,后者通常用于保存程序组件的松耦合度。

例1:利用标准库中定义的各种‘与文件类似’的对象,尽管这些对象的工作方式像文件,但他们没有继承内置文件对象的方法

#二者都像鸭子,二者看起来都像文件,因而就可以当文件一样去用
class TxtFile:
def read(self):
pass

def write(self):
pass

class DiskFile:
def read(self):
pass
def write(self):
pass

例2:其实大家一直在享受着多态性带来的好处,比如Python的序列类型有多种形态:字符串,列表,元组,多态性体现如下

#str,list,tuple都是序列类型
s=str('hello')
l=list([1,2,3])
t=tuple((4,5,6))

#我们可以在不考虑三者类型的前提下使用s,l,t
s.__len__()
l.__len__()
t.__len__()

len(s)
len(l)
len(t)

 





猜你喜欢

转载自www.cnblogs.com/runjam/p/9844818.html