zoukankan      html  css  js  c++  java
  • 用元类和__getattribute__改变类属性的读取方式

    首先,需要知道两点:

    1. 类本身是type类的实例
    2. __getattribute__ 可以改变类实例的属性的读取方式(http://www.cnblogs.com/blackmatrix/p/5681480.html)

    对于__getattribute__,大部分例子都是类似这样的,通过重写类的__getattribute__方法,来改变这个类的实例的属性读取行为

    class ClassA:
        x = 'a'
        def __init__(self):
            self.y = 'b'
        def __getattribute__(self, item):
            return '__getattribute__'
    
    
    if __name__ == '__main__':
        a = ClassA()
        # 使用实例直接访问存在的类属性时,会调用__getattribute__方法
        # 输出结果 __getattribute__
        print(a.x)
        # 使用实例直接访问实例存在的实例属性时,会调用__getattribute__方法
        # 输出结果 __getattribute__
        print(a.y)
        # 使用实例直接访问实例不存在的实例属性时,也会调用__getattribute__方法
        # 输出结果 __getattribute__
        print(a.z)

    但是换个角度想想,类本身也是type类的实例,如果重写type类的子类,也就是元类的__getattribute__的方法,不就可以改变类自身属性的读取行为了吗?

    有这个想法是因为之前写了一个整合自定义异常的类,每个异常是这个类的类属性,每次要抛出异常时,直接raise这个类的类属性就好。

    但是,当某些情况,需要对抛出异常的信息进行修改时,因为这个类是全局的,类属性的修改,会影响到程序其他地方抛出的异常,这明显不合理。

    所以才有了通过重写元类的__getattribute__方法,来改变这个异常类的属性读取过程。

    部分代码:

    class ApiException(Exception):
    
        def __init__(self, err_code, message, status_code=500):
            self.err_code = err_code
            self.status_code = status_code
            self.message = message
    
        def __str__(self):
            return str('异常编号:{code}; Http Code:{status_code}; 异常信息:{message}'.format(
                code=self.err_code,
                status_code=self.status_code,
                message=self.message))
    
    
    class MetaApiExceptions(type):
    
        def __getattribute__(self, item):
            api_ex = super().__getattribute__(item)
            new_api_ex = ApiException(err_code=api_ex['api_code'],
                                      status_code=api_ex['http_code'],
                                      message=api_ex['api_msg'])
            return new_api_ex
    
    
    class ApiBaseExceptions(metaclass=MetaApiExceptions):
    
        def __init__(self):
            pass
    
    
    # API 系统层面异常信息,以1000开始
    class ApiSysExceptions(ApiBaseExceptions):
        # code 1000 为保留编码,代表执行成功
        # 服务不可用
        missing_system_error = {'api_code': 1001, 'http_code': 403, 'api_msg': '服务不可用'}

    通过在type类的子类MetaApiExceptions中,重写__getattribute__方法,每次读取类属性时,会根据原先的类属性(一个dict),实例化出一个异常对象,便于程序中对异常信息进行修改及抛出。

    这样,程序在raise这个类中的某个异常时,获取的都是新实例化的对象,做任何修改都不会影响到其他地方的使用。

    同时,不用在类创建的时候,一次实例化N个异常对象,而是每次使用时在实例化,用完自动回收,更加合理。

  • 相关阅读:
    teamviewer被识别为商用的解决办法
    PLY调试笔记——待解决的问题
    python中的反射
    类的继承顺序
    面向对象---继承
    类成名和命名空间
    面向对象编程
    模块的初始
    装饰器
    列表推导式,生成器
  • 原文地址:https://www.cnblogs.com/blackmatrix/p/6896107.html
Copyright © 2011-2022 走看看