首先,需要知道两点:

  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个异常对象,而是每次使用时在实例化,用完自动回收,更加合理。

用元类和__getattribute__改变类属性的读取方式的更多相关文章

  1. SpringBoot系列四:SpringBoot开发(改变环境属性、读取资源文件、Bean 配置、模版渲染、profile 配置)

    声明:本文来源于MLDN培训视频的课堂笔记,写在这里只是为了方便查阅. 1.概念 SpringBoot 开发深入 2.具体内容 在之前已经基本上了解了整个 SpringBoot 运行机制,但是也需要清 ...

  2. SpringBoot开发(改变环境属性、读取资源文件、Bean 配置、模版渲染、profile 配置)

    1.概念 SpringBoot 开发深入 2.具体内容 在之前已经基本上了解了整个 SpringBoot 运行机制,但是也需要清楚的认识到以下的问题,在实际的项目开发之中,尤其是 Java 的 MVC ...

  3. 3.3 C++改变基类成员在派生类中的访问属性

    参考:http://www.weixueyuan.net/view/6360.html 总结: 使用using声明可以改变基类成员在派生类中的访问属性. private: using book::se ...

  4. python 四种方法修改类变量,实例对象调用类方法改变类属性的值,类对象调用类方法改变类属性的值,调用实例方法改变类属性的值,直接修改类属性的值

    三种方法修改类变量,实例对象调用类方法改变类属性的值,类对象调用类方法改变类属性的值,调用实例方法改变类属性的值,类名就是类对象,city就是类变量, #coding=utf-8 class empl ...

  5. Python基础:17类和实例之一(类属性和实例属性)

    1:类通常在一个模块的顶层进行定义.对于Python来说,声明与定义类是同时进行的. 2:类属性仅与其类相绑定,类数据属性仅当需要有更加“静态”数据类型时才变得有用,这种属性是静态变量.它们表示这些数 ...

  6. C++:调整基类成员在派生类中的访问属性的其他方法(同名成员和访问声明)

    4.3 调整基类成员在派生类中的访问属性的其他方法 4.3.1 同名函数 在定义派生类的时候,C++语言允许在派生类中说明的成员与基类中的成员名字相同,也就是 说,派生类可以重新说明与基类成员同名的成 ...

  7. python 零散记录(七)(下) 新式类 旧式类 多继承 mro 类属性 对象属性

    python新式类 旧式类: python2.2之前的类称为旧式类,之后的为新式类.在各自版本中默认声明的类就是各自的新式类或旧式类,但在2.2中声明新式类要手动标明: 这是旧式类为了声明为新式类的方 ...

  8. 二十六. Python基础(26)--类的内置特殊属性和方法

    二十六. Python基础(26)--类的内置特殊属性和方法 ● 知识框架 ● 类的内置方法/魔法方法案例1: 单例设计模式 # 类的魔法方法 # 案例1: 单例设计模式 class Teacher: ...

  9. 7、存储类 & 作用域 & 生命周期 & 链接属性

    概念解析 存储类 存储类就是存储类型,也就是描述C语言变量在何种地方存储. 内存有多种管理方法:栈.堆.数据段.bss段..text段······一个变量的存储类属性就是描述这个变量存储在何种内存段中 ...

随机推荐

  1. 再学习之Spring(面向切面编程)

    一.概念 1.理论 把横切关注点和业务逻辑相分离是面向切面编程所要解决的问题.如果要重用通用功能的话,最常见的面向对象技术是继承(inheritance)或 组成(delegation).但是,如果在 ...

  2. NOIP2017普及组解题报告

    刚参加完NOIP2017普及,只考了210,于是心生不爽,写下了这篇解题报告...(逃 第一次写博,望dalao们多多指导啊(膜 第一题score,学完helloworld的人也应该都会吧,之前好多人 ...

  3. 大白话Vue源码系列目录

    .first-level{ font-size: 1.2rem; cursor: default; color: #666; } .second-level{ font-size: 1.1rem; p ...

  4. Nexys3学习手记1:写在前面的话

    偶然的机会,结识了xilinx的几位大牛,便毫不客气的从他们的手中接过了基于Spartan-6的由Digilent公司研发的Nexys3开发板(如图1所看到的).记得非常久非常久曾经初识FPGA的时候 ...

  5. 十条很实用的jQuery代码片段

    本文转自:http://developer.51cto.com/art/201604/509093.htm 作者:核子可乐译来源:51CTO 原文标题:10 jQuery Snippets for E ...

  6. java 内存数据存储

    近期在学习的过程中,越发认为基础知识的重要性,so 恶补一下 直接上图上演示样例: 图一:

  7. Uber的成功绝非偶然

    拥有打造一个初创企业并将其做强做大的梦想并不是难事,困难的是怎样将该梦想变成现实.娱乐媒体行业经常将企业成功的过程进行美化,干净利落的将企业成功前所经历的艰苦时刻进行大刀阔斧的剪裁,让其刚好可以达到拍 ...

  8. Mongodb 3.4 + Centos6.5 配置 + mysql.sql转为csv 或 json导入和导出Mongo (64位系统)

    Centos下通过yum安装步骤如下: 声明:相对比那些用源码安装,少了配置和新建log和data目录,这种简单粗暴, ,创建仓库文件, vi /etc/yum.repos.d/mongodb-org ...

  9. java_抽象类

    抽象类1,语法定义抽象类前使用abstract关键字修饰,则该类为抽象类2.应用场景(1)在某些情况下,某个父类只是知道其子类应该包含怎样的方法,但无法准确知道这些子类如何实现这些方法. (2)从多个 ...

  10. gradle发布jar包

    在.gradle文件中添加以下代码 apply plugin: 'application' mainClassName = 'com.excel.ExcelApplication' jar { doF ...