• DAY 19 PYTHON入门


    一、封装
    封装指的就是把数据与功能都整合到一起,听起来是不是很熟悉,没错,我们之前所说的”整合“二字其实就是封装的通俗说法。
    除此之外,针对封装到对象或者类中的属性,我们还可以严格控制对它们的访问,分两步实现:隐藏与开放接口.

    二、隐藏
    Python的Class机制采用双下划线开头的方式将属性隐藏起来(设置成私有的),但其实这仅仅只是一种变形操作,
    类中所有双下滑线开头的属性都会在类定义阶段、检测语法时自动变成“_类名__属性名”的形式:

    这种变形需要注意的问题是:
    1、在类外部无法直接访问双下滑线开头的属性,但知道了类名和属性名就可以拼出名字:_类名__属性,然后就可以访问了,
    如Foo._A__N,所以说这种操作并没有严格意义上地限制外部访问,仅仅只是一种语法意义上的变形。

    2、在类内部是可以直接访问双下滑线开头的属性的,比如self.__f1(),因为在类定义阶段类内部双下滑线开头的属性统一发生了变形。

    3、变形操作只在类定义阶段发生一次,在类定义之后的赋值操作,不会变形。

    三、开放接口
    定义属性就是为了使用,所以隐藏并不是目的

    3.1 隐藏数据属性
    将数据隐藏起来就限制了类外部对数据的直接操作,然后类内应该提供相应的接口来允许类外部间接地操作数据,
    接口之上可以附加额外的逻辑来对数据的操作进行严格地控制

    3.2 隐藏函数属性
    目的的是为了隔离复杂度,例如ATM程序的取款功能,该功能有很多其他功能组成,
    比如插卡、身份认证、输入金额、打印小票、取钱等,而对使用者来说,只需要开发取款这个功能接口即可,其余功能我们都可以隐藏起来

    总结:
    隐藏属性与开放接口,本质就是为了明确地区分内外,类内部可以修改封装内的东西而不影响外部调用者的代码;
    而类外部只需拿到一个接口,只要接口名、参数不变,则无论设计者如何改变内部实现代码,使用者均无需改变代码。
    这就提供一个良好的合作基础,只要接口这个基础约定不变,则代码的修改不足为虑。

    property:
    BMI指数是用来衡量一个人的体重与身高对健康影响的一个指标,计算公式为:
    体质指数(BMI)=体重(kg)÷身高^2(m)
    EX:70kg÷(1.75×1.75)=22.86

    身高或体重是不断变化的,因而每次想查看BMI值都需要通过计算才能得到,但很明显BMI听起来更像是一个特征而非功能,
    为此Python专门提供了一个装饰器property,可以将类中的函数“伪装成”对象的数据属性,对象在访问该特殊属性时会触发功能的执行,然后将返回值作为本次访问的结果,例如
    >>> class People:
    ... def __init__(self,name,weight,height):
    ... self.name=name
    ... self.weight=weight
    ... self.height=height
    ... @property
    ... def bmi(self):
    ... return self.weight / (self.height**2)
    ...
    >>> obj=People('lili',75,1.85)
    >>> obj.bmi #触发方法bmi的执行,将obj自动传给self,执行后返回值作为本次引用的结果
    21.913805697589478

    使用property有效地保证了属性访问的一致性。另外property还提供设置和删除属性的功能.

    classmethod:
    绑定方法与非绑定方法:
    ​ 类中定义的函数分为两大类:绑定方法和非绑定方法
    ​ 其中绑定方法又分为绑定到对象的对象方法和绑定到类的类方法。
    ​ 在类中正常定义的函数默认是绑定到对象的,而为某个函数加上装饰器@classmethod后,该函数就绑定到了类。

    绑定到类的方法就是专门给类用的,但其实对象也可以调用,只不过自动传入的第一个参数仍然是类,
    也就是说这种调用是没有意义的,并且容易引起混淆,这也是Python的对象系统与其他面向对象语言对象系统的区别之一,
    比如Smalltalk和Ruby中,绑定到类的方法与绑定到对象的方法是严格区分开的。

    staticmethod:
    非绑定方法:
    为类中某个函数加上装饰器@staticmethod后,该函数就变成了非绑定方法,也称为静态方法。
    该方法不与类或对象绑定,类与对象都可以来调用它,但它就是一个普通函数而已,因而没有自动传值那么一说

    总结:
    绑定方法与非绑定方法的使用:若类中需要一个功能,该功能的实现代码中需要引用对象则将其定义成对象方法、
    需要引用类则将其定义成类方法、无需引用类或对象则将其定义成静态方法。


    四、继承与派生
    继承:是一种创建新类的方式,在Python中,新建的类可以继承一个或多个父类,新建的类可称为子类或派生类,父类又可称为基类或超类
    python的继承特点:支持多继承
    通过类的内置属性__bases__可以查看类继承的所有父类

    在Python2中有经典类与新式类之分,没有显式地继承object类的类,以及该类的子类,都是经典类,显式地继承object的类,
    以及该类的子类,都是新式类。而在Python3中,即使没有显式地继承object,也会默认继承该类,如下
    >>> ParentClass1.__bases__
    (<class ‘object'>,)
    >>> ParentClass2.__bases__
    (<class 'object'>,)
    因而在Python3中统一都是新式类。
    提示:object类提供了一些常用内置方法的实现,如用来在打印对象时返回字符串的内置方法__str__

    继承与抽象:
    要找出类与类之间的继承关系,需要先抽象,再继承。抽象即总结相似之处,总结对象之间的相似之处得到类,总结类与类之间的相似之处就可以得到父类,
    基于抽象的结果,我们就找到了继承关系,因而继承可以用来解决类与类之间的代码重用性问题。

    属性查找:
    有了继承关系,对象在查找属性时,先从对象自己的__dict__中找,如果没有则去子类中找,然后再去父类中找……
    父类如果不想让子类覆盖自己的方法,可以采用双下划线开头的方式将方法设置为私有的

    继承的实现原理:
    对于你定义的每一个类,Python都会计算出一个方法解析顺序(MRO)列表,该MRO列表就是一个简单的所有基类的线性顺序列表,如下
    >>> F.mro() # 新式类内置了mro方法可以查看线性列表的内容,经典类没有该内置该方法
    [<class '__main__.F'>, <class '__main__.D'>, <class '__main__.B'>,
    <class '__main__.E'>, <class '__main__.C'>, <class '__main__.A'>, <class ‘object’>]

    MRO列表的构造是通过一个C3线性化算法来实现的,我们无需深究该算法的数学原理,它实际上就是合并所有父类的MRO列表,
    且在查找属性时,Python会基于MRO列表按照从左到右的顺序依次查找基类,直到找到第一个匹配这个属性的类为止。

    在Python中子类可以同时继承多个父类,在子类继承了多个父类时,经典类与新式类会有不同MRO,分别对应属性的两种查找方式:深度优先和广度优先

    派生:
    派生与方法重用:
    子类可以派生出自己新的属性,在进行属性查找时,子类中的属性名会优先于父类被查找,例如每个老师还有职称这一属性,我们就需要在Teacher类中定义该类自己的__init__覆盖父类的
    方法一:“指名道姓”地调用某一个类的函数
    方法二:super()
    调用super()会得到一个特殊的对象,该对象专门用来引用父类的属性,且严格按照MRO规定的顺序向后查找

    提示:在Python2中super的使用需要完整地写成super(自己的类名,self) ,而在python3中可以简写为super()。
    这两种方式的区别是:方式一是跟继承没有关系的,而方式二的super()是依赖于继承的,并且即使没有直接继承关系,super()仍然会按照MRO继续往后查找
    关于在子类中重用父类功能的这两种方式,使用任何一种都可以,但是在最新的代码中还是推荐使用super()

    组合:
    在一个类中以另外一个类的对象作为数据属性,称为类的组合。组合与继承都是用来解决代码的重用性问题。
    不同的是:继承是一种“是”的关系,比如老师是人、学生是人,当类之间有很多相同的之处,应该使用继承;而组合则是一种“有”的关系,
    比如老师有生日,老师有多门课程,当类之间有显著不同,并且较小的类是较大的类所需要的组件时,应该使用组合。

  • 相关阅读:
    通过hmc启动lpar的终端
    修复LVM手记
    通过VMLibrary在client partition上安装AIX全程实录
    【转】通过VIOS实现AIX系统的网络虚拟化
    rhel 6 启动流程分析(/etc/inittab)
    Linux中tty、pty、pts的概念区别
    Shell中while循环的done 后接一个重定向<
    搭建dns服务器时报错error: bind: address already in use
    关于 smit mktcpip 和smit chinet 的区别
    博客园博客停更(本博客收集本人于2018年之前的博客,2018年之后的博客统一发布在CSDN上)
  • 原文地址:https://www.cnblogs.com/DEJAVU888/p/14262176.html
Copyright © 2020-2023  润新知