zoukankan      html  css  js  c++  java
  • python 上下文管理器,多态,数据锁定与自省,

    前文课题

    通过装饰器来实现单例模式

    装饰器单例.png

    通过类实现一个通用装饰器,皆可以装饰函数也可装饰类,即可有参也可无参

    类装饰器.png

    描述 new str repr call 分别会在什么时候被触发

    new 创建实例对象的时候

    str print实例对象的时候,str处理对象的时候,format处理对象的时候

    repr 调用repr方法的时候

    call 对象被调用的时候会触发

    上下文管理器

    思考一个问题,python中,with打开文件为什么会自动关闭,是怎么实现的

    with关键字后面跟着的事一个上下文管理对象

    上下文管理器的概念:

    上下文管理器是一个python对象,为操作提供了额外的上下文信息,这种额外的信息,在使用with语句初始化上下文,以及完成with块中的所有代码时,采用可调用的形式

    上下文管理器的实现:

    如果要自己实现上下文管理器,首先要知道上下文管理协议。

    简单来说,就是要在一个类里面实现enter和exit方法,这个类的实例就是一个上下文管理器。

    上下文.png

    在本例中,运行没有抛出异常,就是因为使用了上下文管理器,异常可以在exit进行捕获并且由编写者决定如何处理,是抛出还是在此就解决了,而在exit方法内部返回true(没有return则默认为false),相当于告诉python,这个异常已经捕获了,不需要再向外抛了。

    写exit函数时,需要注意,必须有三个参数:

    exc_type 异常类型,exc_val 异常值 , exc_tb 异常的错误栈信息,也就是异常回溯信息。

    而当代码没有异报异常的时候,三个参数都为None

    观察执行可以看出,在编写代码的时候可以将资源的连接或者获取放在 __enter__中,将资源的关闭卸载放在__exit__中。

    看一个实际应用: 需求 ,利用上下文管理器编写一个连接DB返回游标的类。

    # 实现一个操作mysql的上下文管理器,可以自动断开连接
     1 import pymysql
     2 class DB:
     3 
     4    def __init__(self, **data_conf):
     5       # 初始化db ,
     6       self.conn = pymysql.connect(**data_conf)
     7       self.cursor = self.con.cursor()
     8 
     9    def __enter__(self):
    10       # 将游标返回到上下文中
    11       return self.cursor
    12 
    13    def __exit__(self, exc_type, exc_val, exc_tb):
    14       self.cursor.close()
    15       self.conn.close()
    16 
    17 
    18 # 以元祖格式书写,直接强转成dict
    19 DB_conf = dict(
    20    host='localhost',
    21    user='root',
    22    password='123456',
    23    port=3306,
    24    charset='utf8'
    25 )
    26 print(type(DB_conf))
    27 print(DB_conf)
    28 # with 后面跟的是一个函数主题,也可以是自定义的类
    29 with DB(DB_conf) as cur:  # cur 作为enter方法返回的上下文句柄,是db的游标
    30    cur.execute('sql')
    31    print(cur.fetchone())
    32 
    33 # 描述slots属性的作用,并修改读取excel类中保存用例的类
    34 # 限制对象属性,指定指定的slots的属性
    35 # 节约内存
    36 class Case:
    37    __slots__ = ['case_id','title','url','data']
    38    def __int__(self):
    39       self.case_id = None
    40       self.title = None
    41       self.url = None
    42       self.data = None
    43 # 在进行实例化的时候 只能生成被slots进行指定的对象属性,且不会自动生成占用内存量大的__dict__
    44 # 使用场景主要是需要大量创建对象的时候,比如excel读取
     

    使用上下文管理器可以使代码更优雅。

    多态

    面向对象变成的三大特征,封装,继承,多态

    # 封装,将数据和方法放在一个类中构成封装
    # 继承 python中一个类可以继承于一个类也可以继承于多个类,被继承的类叫做父类或者基类
    # 继承的类叫做子类
    # 多态 指的事一类事物有多种形态,,噫个抽象类有多个子类(因而多态的概念依赖于继承
    # 不同的子类对象调用相同的方法,产生不同的执行结果,多态可以增加代码的灵活程度
    
    # 多态是建立在继承的基础上的
    # python中的多态是伪多态
    # python中函数的参数是没有类型限制的,传啥玩意儿都行
    

    实现多态的方法

    定义一个父类,实现某个方法

    定义多个子类,子类中重写父类的方法,每个子类方法实现不同的功能。

    假如定义了一个函数,需要一个base类型的对象的参数,那么调用函数的时候传入类型应当为base

    不同的子类对象,那么这个函数就会执行不同的功能,就是多态的体现

    多态的意义

    开放封闭原则

    对于一个变量,只需要知道它是base类型,无需确切的知道他的子类型就可以放心的调用run方法,调用方只管调用,不管内部细节

    当需要新增功能,只需要新增一个base的子类实现run方法,就可以在原来的基础上进行扩展

    就是开放封闭原则,对扩展开放,允许增加新的base子类,对修改封闭,不需要修改依赖base类型的run等函数

    鸭子类型

    概念, 并不要求严格的继承体系,关注的不是对象的类型本身,而是如何使用的,

    一个对象只要看起来像鸭子,走起路来像鸭子,就可以看做是鸭子

    鸭子类型的体现

    静态语言,对于静态语言 java c# 来讲,上面传入的对象必须是base类型或者它的子类,否则将无法调用run方法

               动态语言 对于动态语言python来讲,上面传入的并不一定要是base类型,也可以是其他类型,只要在内部实现一个run方法就行了,这就是鸭子类型的体现

    数据和自省

    私有属性定义

    单下划线开头的私有属性

    双下滑线开头的私有属性

    两者之间的区别

    首先,py中没有真正的私有化支持,但可用下划线得到伪私有,有一项大多数python代码都遵循的习惯,

    带有下划线前缀名称都应当被视为不可更改的api的一部分(无论是函数,方法,还是数据成员。

    它应该被视为实现细节,如有更改,不另行通知

    访问:

    类属性可以通过类和实例对象去访问,

    单下划线开头的私有属性也可以被类和实例访问

    双下划綫开头的私有属性,对外不可直接访问,为了保护这个变量,进行了改名

    改名的具体规则则是 在原有的基础上添加了 _类名 ,整体变为 _类名__属性名

    只有在使用新名字去访问的时候才可以访问到双下划綫修饰的变量

    私有属性.png

    dict 与 slots

     1 # __dict__
     2 # 类调用 ,返回类属性和方法的字典
     3 # 实例对象调用dict,返回实例中的数据行和方法的字典
     4 # 因为dict的存在会导致内存的消耗
     5 
     6 # 内置属性 __slots__
     7 # 默认情况下,类的实例有一个字典用于存储属性,这对于具有很少
     8 
     9 # 限制对象的属性
    10 #
    11 class Base(object):
    12    __slots__ = ['name']  # 指定类对象所能绑定的属性
    13 
    14 
    15 b = Base()
    16 # b.age =200  # 'Base' object has no attribute 'age'
    17 b.name = '阿迪'
    18 print(b.__dict__  )  #  'Base' object has no attribute '__dict__'
    19 # 定义了slots之后,就没有dict对象了,
    20 # slots可以做一个属性限制,,还有节约内存,定义了slots属性之后,该对象不会再自动
    21 # 生成 __dict__属性,
    22 
    23 # 那么为什么dict会占用内存呢?
    24 # 创建对象会自动生成dict,是一个字典,字典会首先划开一个比较大的内存空间
    25 # 加入说一个用例里面有很多属性 dict占用内存就会很多
    26 # __slots的话就会对所有对象属性进行限制,

     

  • 相关阅读:
    centos8 将SSSD配置为使用LDAP并要求TLS身份验证
    Centos8 搭建 kafka2.8 .net5 简单使用kafka
    .net core 3.1 ActionFilter 拦截器 偶然 OnActionExecuting 中HttpContext.Session.Id 为空字符串 的问题
    Springboot根据不同环境加载对应的配置
    VMware Workstation12 安装 Centos8.3
    .net core json配置文件小结
    springboot mybatisplus createtime和updatetime自动填充
    .net core autofac依赖注入简洁版
    .Net Core 使用 redis 存储 session
    .Net Core 接入 RocketMQ
  • 原文地址:https://www.cnblogs.com/addicated/p/13167351.html
Copyright © 2011-2022 走看看