用元类和__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段······一个变量的存储类属性就是描述这个变量存储在何种内存段中 ...
随机推荐
- 深入研究-webkit-overflow-scrolling:touch及ios滚动
1. -webkit-overflow-scrolling:touch是什么? MDN上是这样定义的: -webkit-overflow-scrolling 属性控制元素在移动设备上是否使用滚动回弹效 ...
- 使用PowerApps快速构建基于主题的轻业务应用 —— 入门篇
作者:陈希章 发表于 2017年12月12日 前言 在上一篇文章 基于Office 365的随需应变业务应用平台 中我提到,随着随需应变的业务需要,以及技术的发展,业务应用的开发的模式也有了深刻的变化 ...
- 41.Linux应用调试-修改内核来打印用户态的oops
1.在之前第36章里,我们学习了通过驱动的oops定位错误代码行 第36章的oops代码如下所示: Unable to handle kernel paging request at //无法处理内核 ...
- TortoiseSVN的安装和使用
TortoiseSVN是windows平台下Subversion的免费开源client. 一般我们都是先讲讲server的配置.然后再讲client的使用,可是在TortoiseSVN上.却能够反过来 ...
- Laravel技巧之记录多日志
相信每个小伙伴在使用laravel的时候都会记录日志.查看日志.那么问题来了,比如我在对接zabbix接口的时候,使用 Log::info() 会让日志全部记录在 storage/logs/larav ...
- tomcat加入系统服务+开机自启
1.首先将tomcat/bin 下的catalina.sh复制到目录/etc/init.d中,并修改名称为tomcat [root@iZ2318 ~]# sudo cp /usr/local/tomc ...
- 「mysql优化专题」这大概是一篇最好的mysql优化入门文章(1)
优化,一直是面试最常问的一个问题.因为从优化的角度,优化的思路,完全可以看出一个人的技术积累.那么,关于系统优化,假设这么个场景,用户反映系统太卡(其实就是高并发),那么我们怎么优化? 如果请求过多, ...
- docker commit使用
我们运行的容器可能在镜像的基础上做了一些修改,有时候我们希望保存起来,封装成一个更新的镜像 docker自己提供的有commit功能 我们以centos为例,现在我们要在一个裸的centos上面安装v ...
- 使用canvas实现绚丽的时钟特效
源码 https://github.com/2016Messi/Gorgeous-clock 效果展示 https://2016messi.github.io/Gorgeous-clock/ 如果各位 ...
- SQL 杂活
例子一:查询两个表数据并且分页展示 select * from ( select ROW_NUMBER() OVER(order by CreateTime desc) as rownum,* fro ...