python第四章

详解python面对对象

Posted by QQL on October 3, 2018

面向对象3大特性

封装

简述:方法封装到来类中(函数封装到类中,并且第一个参数为self,变成方法);数据封装到对象中(__init__中,添加参数数据)
私有属性/方法:封装后,__开头的属性或函数不能再外部调用,否则会报错。在类的内部依然可以访问
其实这仅仅这是一种变形操作,类中所有双下划线开头的名称如__x都会自动变形成:_类名__x的形式
而__x(self)这种方法在类的定义阶段就已经进行了变形成_类名__x 示例:
封装.jpg
实例
flask中

  • session/request封装到来RequestContext对象中
  • app/g封装到了AppContext中

    继承

    简述:如果多各类中有相同的方法,为了避免重复编写,可以将其放在父类(基类)中
    python中类的继承分为:单继承和多继承
    查看类继承的父类__base__或__bases__,示例:
    __base__只查看从左到右继承的第一个子类,bases__则是查看所有继承的父类
    ` (<class ‘__main
    .ParentClass1’>,) `
    经典类与新式类
    1.只有在python2中才分新式类和经典类,python3中统一都是新式类
    2.在python2中,没有显式的继承object类的类,以及该类的子类,都是经典类
    3.在python2中,显式地声明继承object的类,以及该类的子类,都是新式类
    4.在python3中,无论是否继承object,都默认继承object,即python3中所有类均为新式类
    继承实现的原理
    F.mro() 等同于F.__mro__ 生成简单的所有基类的线性顺序列表,且从左到右进行匹配
    应用:Flask: wtforms中meta使用(meta作用定制csrf token) 注意!只有新式类有__mro__
    深度优先(按照基类一路往下走到底)和广度优先(走到倒数第二个,倒回来重新走第二个参数基类)
    当类是经典类(python2不继承object)时,多继承情况下,再要查找属性不存在时,会按照深度优先的方式查找下去
    当类是新式类(python2继承object/python3)时,多继承情况下,再要查找属性不存在时,会按照广度优先的方式查找下去
    在子类中调用父类的方法
    方式一:指名道姓,即父类名.父类方法()
    示例
    继承1.jpg
    方式二:super()
    示例继承2.jpg
    这两种方式的区别是:方式一是跟继承没有关系的,而方式二的super()是依赖于继承的,并且即使没有直接继承关系, super仍然会按照mro继续往后查找
    实例
    Django中
    rest framework中的视图类的继承

    多态

    简述:鸭子模型:天生支持多态,对于参数来说可以传入任何类型的对象,只要保证有想要的send方法即可
    简述:通过一个接口(函数),进行反复调用,达到同样的结果
    因为python是非强类型的语言,例如,传入的参数或者给的某个值,只要有某个方法存在我就认为他是某一个类型,所以本身就是多态
    实例
    list()/dict()等实例对象,可调用append(),insert(),pop()等相同的方法,就是多态性

    面向对象程序设计与面向过程程序设计

    面向过程:一般用于那些功能一旦实现之后就很少需要改变的场景, 如果你只是写一些简单的脚本,去做一些一次性任务,用面向过程的方式是极好的,著名的例子有Linux內核,git,以及Apache HTTP Server等
    面向对象:如果你要处理的任务是复杂的,且需要不断迭代和维护 的

    一切皆对象

    python中一切皆为对象,且python3中类与类型是一个概念,类型就是类
    多个对象都有绑定方法func,是相同的功能,但内存地址不同
    操作绑定方法,因为内存地址不同,所以不会相互影响
    重用性有两种方式
    继承:详情看上述内容
    组合:组合指的是,在一个类中以另外一个类的对象作为数据属性,称为类的组合,即:
    类的__init__中:self.coursename = Course() # 其中,这个Course()为另外一个类的对象
    使用场景:当类之间有显著不同,并且较小的类是较大的类所需要的组件时,用组合比较好
    总结:扩充类的功能,合并其他类的方法

    接口

    定义:接口是一组功能的入口,要调用某一组功能,需要通过接口来进行调用,而不需要关注这组功能是如何实现的,要的只是结果。
    应用:基类定义成抽象类,为派生类提供接口,如果派生类不定义接口的方法,那么无法使用,目的为了约束实现该接口的类中必须定义指定的某些方法

    抽象类:

    把相同的特征抽象到一个类中,使用方法和继承没什么区别,只需要导入import abc
    定义的抽象类,无需实现功能
    抽象类不能实例化,只能被继承
    抽象类是用来规定类的格式的,抽象类有的方法,继承他的子类就必须有他的方法
    为多态性进行铺垫
    示例
    抽象类.jpg
    实际开发中不会使用abc这种方法,而会使用抛出异常的方法进行类的规定!!
    使用:raise NotImplementedError(“继承的类需要实现该方法”)
    当实例化的对象调用该抛异常方法时,如果没有重写该方法,则会抛出NotImplementedError
    示例
    抽象类2.jpg

    绑定方法与非绑定方法

    绑定方法
    绑定给对象(在类中的方法第一个参数为self都是绑定给对象的)
    绑定给类(classmehtod是给类用的,即绑定到类,类在使用时会将类本身当做参数传给类方法的第一个参数)
    非绑定方法
    在类内部用staticmethod装饰的函数即非绑定方法,就是普通函数,谁都可以调用,且没有自动传值
    对比示例
    对比.jpg

    查看名称空间

    对象__dict__ 类在定义的时候创建的名称空间,类的变量,类体里的函数function
    其中,私有属性或方法__x在定义时变形为:_类名__x

    类的内部获取当前运行的 class 的名字:self.__class__.__name__

    内置方法

    isinstance(obj,cls)检查是否obj是否是类 cls 的对象,相当于加强版的type(),可以检查出继承
    反射:访问、检测和修改它本身状态或行为的一种能力(自省)
    自省函数
    自省.jpg
    反射的好处
    实现可插拔机制
    动态导入模块
    setattr/delattr/__getattr__应用时会出现的一些问题
    __setattr__.jpg

    描述符!!!

  • __get__(self, instance, owner) instance:当前对象/owner:实例化对象的类本身
  • __set__(self, instance, value) instance:当前对象/value设置的值
  • __delete__(self, instance) instance:当前对象
  • 定义
    新式类实现了这三个方法的类就是描述符,作用是用来代理另外一个类的属性的
    另一个类调用/赋值修改/del删除一个属性时,触发描述符的执行,描述符本身无法触发
    在一个类中定义描述符它就是一个类属性,存在于类的属性字典中,而不是对象的属性字典,所以描述符对类没有作用
  • 描述符分类
    数据描述符:至少实现了__get__,__set__方法
    非数据描述符:没有实现__set__方法(函数就是一个由非描述符类实例化得到的对象,字符串也一样)
  • 调用优先级
  • 类属性
  • 数据描述符
  • 实例属性
  • 非数据描述符
  • 找不到属性触发__getattr__()
  • 应用
    实现:@property、@classmethod、@staticmethod
  • 描述符总结
    描述符是可以实现大部分python类特性中的底层魔法,包括@classmethod,@staticmethd,@property甚至是__slots__属性
    描述父是很多高级库和框架的重要工具之一,描述符通常是使用到装饰器或者元类的大型框架中的一个组件

    内置方法

    __setitem__/__getitem__/__delitem__/__delattr__
    详情
    内置方法1.jpg
    __str__,__repr__,__format__
    改变对象的字符串显示__str__,__repr__(触发场景:使用print()触发)
    str函数或者print函数—>obj.__str__()
    repr或者交互式解释器—>obj.__repr__()
    如果__str__没有被定义,那么就会使用__repr__来代替输出
    注意:这俩方法的返回值必须是字符串,否则抛出异常,两个都存在时候,__str__优先级高
    自定制格式化字符串__format__(触发场景:使用format触发)
    issubclass和isinstance

  • issubclass:判断基类派生类
    print(issubclass(B,A)) #B是A的子类,返回True
  • isinstance:判断对象和类
    print(isinstance(a1,A)) #a1是A的实例 __slots__
    限制绑定属性,__slots__ = ('name', 'age') 用tuple定义允许绑定的属性名称,则不能在外界绑定其他的属性,否则会错。__slots__定义的属性仅对当前类实例起作用,对继承的子类是不起作用的
    触发场景:直接在类中设置属性 __slots__=['name','age']
    __doc__
    它类的注释描述信息,通常运用到元类、抽象类中,用来规定类的样式
    该属性无法被继承
    触发场景:在类中编写注释”"”content”””
    __next__和__iter__
    实现迭代器iterator协议
    触发场景
    如果类中实现了__iter__则可以被循环
    当进行.next()的时候调用__next__
    __module__和__class__
    __module__ 表示当前操作的对象在哪个模块
    __class__ 表示当前操作的对象的类是什么
    触发场景:直接用对象进行调用 obj.__module__/obj.__class__
    __del__
    析构方法,当对象在内存中被释放时,自动触发执行
    触发场景
    一个对象有用户级与内核级两种资源,比如(打开一个文件,创建一个数据库链接),则必须在清除对象的同时回收系统资源,这就用到了__del__
    文件f.close()/数据库conn.close()
    __enter__和__exit__
    with open('a.txt') as f:
      '代码块'
    

    上述叫做上下文管理协议,即with语句,为了让一个对象兼容with语句,必须在这个对象的类中声明__enter____exit__方法
    详情:
    内置方法2.jpg
    __call__
    触发场景:对象后面加括号,触发执行。
    详情
    内置方法3.jpg
    __new__
    实例化对象时真正的构造方法
    详情
    内置方法4.jpg
    ##元类:
    元类是类的类,是类的模板。元类是用来控制如何创建类的
    创建类的两种方式
    方式一:使用class关键字
    方式二:就是手动模拟class创建类的过程):将创建类的步骤拆分开,手动去创建
    详情
    内置方法5.jpg
    类的执行顺序!!
    元类的__init__在类的创建已经触发
    元类的__call__返回类实例化的obj
    类的__new__
    类的__init__
    详情:

    类中各语句的执行顺序

    解析顺序

  • 静态
  • 继承管理
  • 构造
    执行顺序
  • 静态
  • 构造
  • 继承

    异常处理

    常见异常

  • AttributeError 试图访问一个对象没有的树形,比如foo.x,但是foo没有属性x
  • IOError 输入/输出异常;基本上是无法打开文件
  • ImportError 无法引入模块或包;基本上是路径问题或名称错误
  • IndentationError 语法错误(的子类) ;代码没有正确对齐
  • IndexError 下标索引超出序列边界,比如当x只有三个元素,却试图访问x[5]
  • KeyError 试图访问字典里不存在的键
  • KeyboardInterrupt Ctrl+C被按下
  • NameError 使用一个还未被赋予对象的变量
  • SyntaxError Python代码非法,代码不能编译(个人认为这是语法错误,写错了)
  • TypeError 传入对象类型与要求的不符合
  • UnboundLocalError 试图访问一个还未被设置的局部变量,基本上是由于另有一个同名的全局变量, 导致你以为正在访问它 ValueError 传入一个调用者不期望的值,即使值的类型是正确的
  • 更多常用异常:
    StopIteration 迭代器/生成器没有值了
    NotImplementedError 用来做接口约束
    Exception 捕捉所有异常
    自定义异常
    自定义异常.jpg
    断言:assert 条件