用元类和__getattribute__改变类属性的读取方式
首先,需要知道两点:
- 类本身是type类的实例
- __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__改变类属性的读取方式的更多相关文章
- SpringBoot系列四:SpringBoot开发(改变环境属性、读取资源文件、Bean 配置、模版渲染、profile 配置)
声明:本文来源于MLDN培训视频的课堂笔记,写在这里只是为了方便查阅. 1.概念 SpringBoot 开发深入 2.具体内容 在之前已经基本上了解了整个 SpringBoot 运行机制,但是也需要清 ...
- SpringBoot开发(改变环境属性、读取资源文件、Bean 配置、模版渲染、profile 配置)
1.概念 SpringBoot 开发深入 2.具体内容 在之前已经基本上了解了整个 SpringBoot 运行机制,但是也需要清楚的认识到以下的问题,在实际的项目开发之中,尤其是 Java 的 MVC ...
- 3.3 C++改变基类成员在派生类中的访问属性
参考:http://www.weixueyuan.net/view/6360.html 总结: 使用using声明可以改变基类成员在派生类中的访问属性. private: using book::se ...
- python 四种方法修改类变量,实例对象调用类方法改变类属性的值,类对象调用类方法改变类属性的值,调用实例方法改变类属性的值,直接修改类属性的值
三种方法修改类变量,实例对象调用类方法改变类属性的值,类对象调用类方法改变类属性的值,调用实例方法改变类属性的值,类名就是类对象,city就是类变量, #coding=utf-8 class empl ...
- Python基础:17类和实例之一(类属性和实例属性)
1:类通常在一个模块的顶层进行定义.对于Python来说,声明与定义类是同时进行的. 2:类属性仅与其类相绑定,类数据属性仅当需要有更加“静态”数据类型时才变得有用,这种属性是静态变量.它们表示这些数 ...
- C++:调整基类成员在派生类中的访问属性的其他方法(同名成员和访问声明)
4.3 调整基类成员在派生类中的访问属性的其他方法 4.3.1 同名函数 在定义派生类的时候,C++语言允许在派生类中说明的成员与基类中的成员名字相同,也就是 说,派生类可以重新说明与基类成员同名的成 ...
- python 零散记录(七)(下) 新式类 旧式类 多继承 mro 类属性 对象属性
python新式类 旧式类: python2.2之前的类称为旧式类,之后的为新式类.在各自版本中默认声明的类就是各自的新式类或旧式类,但在2.2中声明新式类要手动标明: 这是旧式类为了声明为新式类的方 ...
- 二十六. Python基础(26)--类的内置特殊属性和方法
二十六. Python基础(26)--类的内置特殊属性和方法 ● 知识框架 ● 类的内置方法/魔法方法案例1: 单例设计模式 # 类的魔法方法 # 案例1: 单例设计模式 class Teacher: ...
- 7、存储类 & 作用域 & 生命周期 & 链接属性
概念解析 存储类 存储类就是存储类型,也就是描述C语言变量在何种地方存储. 内存有多种管理方法:栈.堆.数据段.bss段..text段······一个变量的存储类属性就是描述这个变量存储在何种内存段中 ...
随机推荐
- JavaScript学习笔记(一)数组排序
数组(Array)在JavaScript中是非常常用的类型,关于数组的排序,与C#等语法中的排序,乍看相似,其实差别比较大. Array的排序方法有两个,分别是reverse()和sort(). re ...
- Linux定义变量的脚本
现有两段基本一样的代码,只是变量进行改变,其他都没有变化,但是执行过程中出现了不一样的结果 代码一: vi back.sh #backup import file,such as /etc/rc.lo ...
- NDK开发过程自认为好的一些参考资料
虽然NDK开发时间很短, 但也接触了一些自认为还不错的资料, 记录下来. 一.首先就说官方文档吧 网上资料好多过时了, 并且有点参差不齐. 所以看官方文档还是很有必要的,我根据我的需求整理了两个的链接 ...
- 《重构--改善既有代码的设计》总结or读后感:重构是程序员的本能
此文写得有点晚,记得去年7月读完的这本书,只是那时没有写文章的意识,也无所谓总结了,现在稍微聊一下吧. 想起写这篇感想,还是前几天看了这么一篇文章 研究发现重构软件并不会改善代码质量 先从一个大家都有 ...
- Android之通过网络播放一首简单的音乐
首先,附上程序执行后的效果.例如以下图所看到的: 一.部署一个web项目到tomcatserver上: 1.这个小程序是结合网络来播放一首音乐的,首先,把我们搞好的一个web项目放置在tomcat安装 ...
- Android笔记(五)利用Intent启动活动
Intent是意图的意思,分为显式 Intent 和隐式 Intent. 以下我们试图在FirstActivity中通过点击button来启动SecondActivity 1.显式Intent 在应用 ...
- 【我们都爱Paul Hegarty】斯坦福IOS8公开课个人笔记38 Unwind Segue反向过渡
之前我们接触过了segue,这是IOS中最主要的传递方式,今天来解说一下怎样进行反向的segue. 反向过渡的使用前提是发出过渡的MVC必须是由目标MVC直接或者间接正向过渡来的.反向过渡是唯一不会创 ...
- 本地IIS
一,搭建IIS 要建立本地的IIS需要进行以下操作(包括显示.NET): 开始=>控制面板(查看方式为类别)=>程序=>程序和功能=>左边的打开或关闭Windows功能选中以下 ...
- Java并发编程有多难?这几个核心技术你掌握了吗?
本文主要内容索引 1.Java线程 2.线程模型 3.Java线程池 4.Future(各种Future) 5.Fork/Join框架 6.volatile 7.CAS(原子操作) 8.AQS(并发同 ...
- selenium.common.exceptions.WebDriverException: Message: 'phantomjs' executab
该问题博主是在Mac环境遇到的,对应windows找对应解决方案解决即可. 问题原因: phantomjs环境配置有问题,要么是配置错误,要么是没有配置. 解决方案: 1.将下载解压好的phantom ...