Python的__getattribute__二三事
本来以为自己对__getattribute__已经比较了解了,结果用到的时候,才发现有一些知识点之前一直没有真正弄明白,记录如下(针对python3,python2差异较大):
- object类有__getattribute__属性,因此所有的类默认就有__getattribute__属性(所有类都继承自object),object的__getattribute__起什么用呢?它做的就是查找自定义类的属性,如果属性存在则返回属性的值,如果不存在则抛出AttributeError。
还是看代码:
>>> class A:
def __getattribute__(self, name):
print('in A')
return super().__getattribute__(name)
>>> class B(A):
def spam(self):
print('spam')
>>> b = B()
>>> in A
b.spam()
in A
spam
当在命令行输入b.spam(,甚至括号还没有输入完整的时候,就已经触发了__getattribute__。可见,当实例在查找任何属性的时候(注意是实例,这是另一个知识点,后面再详谈),都会触发__getattribute__方法。
基于此特性,可以方便的使用类装饰器为其所有属性(不管是有的还是没有的)扩充功能,例如,加一个log记录功能,代码如下:
>>> def log_attr(cls):
cls_getattribute = cls.__getattribute__
def new_getattribute(self, name):
print('catch name')
return cls_getattribute(self, name)
cls.__getattribute__ = new_getattribute
return cls
>>> @log_attr
class C:
def __init__(self, x):
self.x = x
def spam(self):
print('spam')
>>> c = C(42)
>>> c.x
catch name
42
>>> catch name
c.spam()
catch name
spam
>>> c.y
catch name
Traceback (most recent call last):
File "<pyshell#83>", line 1, in <module>
c.y
File "<pyshell#77>", line 5, in new_getattribute
return cls_getattribute(self, name)
AttributeError: 'C' object has no attribute 'y'
- 只有在实例的命名空间查找属性的时候,才会触发__getattribute__,在类的命名空间中查找,是不会触发__getattribute__的。
还是第一个例子:
>>> B.spam
<function B.spam at 0x000001D3759646A8>
>>> b = B()
>>> B.spam(b)
spam
可见,当类直接调用spam方法的时候,不会触发__getattribute__,而且当以B.spam(b)形式调用的时候,巧妙的绕过了__getattribute__。
接下来,是一个重要的知识点,即特殊的方法,如__len__,__str__等等操作符重载方法,当隐式调用的时候,在python3中会直接在类的命名空间中查找,因此是不会触发__getattribute__的!!如下:
>>> class C:
def __len__(self):
return 42
def __getattribute__(self, name):
print(f'catch {name}')
return super().__getattribute__(name)
>>> c = C()
>>> len(c)
42
but,当直接显示调用的时候,python不会将其当作啥特殊方法,仍然会从实例的命名空间查找,此时,就会触发__getattribute__:
>>> c.__len__()
catch __len__
42
最大的影响就是,在委托类型的代码中,操作符重载的方法代码得重新写,如下:
>>> class A:
def __len__(self):
return 42
def attr1(self):
print('attr1')
>>> class B:
def __init__(self):
self.a = A()
def __getattribute__(self, name):
if name == 'a':
return super().__getattribute__(name)
else:
return getattr(self.a, name)
>>> b.attr1()
attr1
>>> len(b)
Traceback (most recent call last):
File "<pyshell#170>", line 1, in <module>
len(b)
TypeError: object of type 'B' has no len()
可见,attr1正确的被代理,但是len方法没有被代理,因为隐式调用的时候,直接在B类的命名空间查找__len__方法,根本就没有触发__getattribute__。如果显示调用,就可以被代理了。
>>> b.__len__()
42
最后,还有一个坑需要注意,如上例B类的__getattribute__方法中,判断一下a是否B自身的实例属性的代码不可少,是则调用父类的__getattribute__方法返回正确的self.a,否则在getattr(self.a, name)中,self.a会不断的触发__getattribute__,从而会陷入无限循环。
对了,最后还有一小点,有一个比较特殊的操作符重载方法,即dir,因为它会从实例的命名空间开始查找__dict__和__class__特殊方法,因此也会触发__getattribute__。
貌似关于__getattribute__的知识点就这些了,以上均为个人原创,平时学习的积累,打字不易,转载还请注明出处。
Python的__getattribute__二三事的更多相关文章
- Python中字符串二三事
首先说两个运算符: " == " 运算符测试值的等价性,递归地比较所有内嵌对象 " is " 表达式测试对象的同一性,测试两者是否为同一对象(是否为同一地址) ...
- python basemap readshapefile二三事
今天要用到basemap读取shp文件报错,查了很多资料,都没有解决. 先是: fig,ax = plt.subplots(figsize=(15,10)) from mpl_toolkits.bas ...
- python基础---- __getattribute__----__str__,__repr__,__format__----__doc__----__module__和__class__
目录: 一. __getattribute__ 二.__str__,__repr__,__format__ 三.__doc__ 四.__module__和__class__ 一. __getattri ...
- python排序之二冒泡排序法
python排序之二冒泡排序法 如果你理解之前的插入排序法那冒泡排序法就很容易理解,冒泡排序是两个两个以向后位移的方式比较大小在互换的过程好了不多了先上代码吧如下: 首先还是一个无序列表lis,老规矩 ...
- Python 基础语法(二)
Python 基础语法(二) --------------------------------------------接 Python 基础语法(一) ------------------------ ...
- Java并发编程二三事
Java并发编程二三事 转自我的Github 近日重新翻了一下<Java Concurrency in Practice>故以此文记之. 我觉得Java的并发可以从下面三个点去理解: * ...
- linux杂记(十二?) 关于账号和密码的二三事
关于密码的二三事 关于账号和密码的二三事 久了不更linux的相关知识,实在是懒得想内容点(纯粹是懒).那么今天就来谈谈关于linux密码和账号的重要概念. 假如你的主机遭到入侵,那么对方的第一个侵入 ...
- Python 数据分析(二 本实验将学习利用 Python 数据聚合与分组运算,时间序列,金融与经济数据应用等相关知识
Python 数据分析(二) 本实验将学习利用 Python 数据聚合与分组运算,时间序列,金融与经济数据应用等相关知识 第1节 groupby 技术 第2节 数据聚合 第3节 分组级运算和转换 第4 ...
- 初学 Python(十二)——高阶函数
初学 Python(十二)--高阶函数 初学 Python,主要整理一些学习到的知识点,这次是高阶函数. #-*- coding:utf-8 -*- ''''' 话说高阶函数: 能用函数作为参数的函数 ...
随机推荐
- Jenkins中Jelly邮件模板的配置
[链接]Jenkins中Jelly邮件模板的配置http://blog.csdn.net/hwhua1986/article/details/47975237
- 微信小程序文档里看不到的小Tips
前几天折腾了下.然后列出一些实验结果,供大家参考. 0. 使用开发工具模拟的和真机差异还是比较大的.也建议大家还是真机调试比较靠谱. 1. WXML(HTML) 1.1 小程序的WXML没有HTML的 ...
- fastdfs 上传和下载 有用
一.FastDFS解决什么样的问题 1.存储空间可扩展. 2.提供一个统一的访问方式. 使用FastDFS,分布式文件系统.存储空间可以横向扩展,可以实现服务器的高可用.支持每个节点有备份机. 二.什 ...
- SQL Server 2008 收缩日志
如果SQL SERVER 日志过大,比如,达到了几十个G,想一次性收缩的,直接执行下面命令即可: USE DATABASENAME; GO – Truncate the log by changing ...
- 设计模式--单例模式(Singleton)详解
单例对象(Singleton)是一种常用的设计模式.在Java应用中,单例对象能保证在一个JVM中,该对象只有一个实例存在.这样的模式有几个好处: 1.某些类创建比较频繁,对于一些大型的对象,这是一笔 ...
- 黑盒测试实践-任务进度-Day05
任务进度11-30 使用工具 selenium 小组成员 华同学.郭同学.穆同学.沈同学.覃同学.刘同学 任务进度 经过了前两天的学习任务的安排,以下是大家的任务进度: 华同学(任务1) 1.由于昨天 ...
- springboot+swagger集成
一.swagger介绍 Swagger 是一款RESTFUL接口的文档在线自动生成+功能测试功能软件.本文简单介绍了在项目中集成swagger的方法和一些常见问题.如果想深入分析项目源码,了解更多内容 ...
- NBA常识 位置的划分 足球:越位等于抢跑
篮球:1号位——组织后卫(控球,组织)2号位——得分后卫(中远投篮,突破)3号位-----小前锋(突破,中远投篮)4号位——大前锋(二中锋,篮板,背身单打,禁区防守)5号位——中锋(篮板.背身单打,禁 ...
- 策略和计费控制(PCC)系统研究
策略和计费控制(PCC)系统研究 研究内容 [TOC "float:left"] 策略与计费控制(PCC)框架1 [架构图](achitecture.png "Archi ...
- MongoDB YAML格式的配置文件
根据官网的提示内容,默认的配置文件内容为 systemLog: verbosity: 0 quiet: false # traceAllExceptions: <boolean> sysl ...