python属性查找 深入理解(attribute lookup)
在Python中,属性查找(attribute lookup)是比较复杂的,特别是涉及到描述符descriptor的时候。
在上一文章末尾,给出了一段代码,就涉及到descriptor与attribute lookup的问题。而get系列函数(__get__, __getattr__, __getattribute__) 也很容易搞晕,本文就这些问题简单总结一下。
首先,我们知道:
python中一切都是对象,“everything is object”,包括类,类的实例,数字,模块
任何object都是类(class or type)的实例(instance)
如果一个descriptor只实现了__get__方法,我们称之为non-data descriptor, 如果同时实现了__get__ __set__我们称之为data descriptor。
按照python doc,如果obj是某个类的实例,那么obj.name首先调用__getattribute__。如果类定义了__getattr__方法,那么在__getattribute__抛出 AttributeError 的时候就会调用到__getattr__,而对于描述符(__get__)的调用,则是发生在__getattribute__内部的。官网文档是这么描述的
The implementation works through a precedence chain that gives data descriptors priority over instance variables, instance variables priority over non-data descriptors, and assigns lowest priority to
__getattr__()
if provided.
obj = Clz(), 那么obj.attr 顺序如下:
(1)如果“attr”是出现在Clz或其基类的__dict__中, 且attr是data descriptor, 那么调用其__get__方法, 否则
(2)如果“attr”出现在obj的__dict__中, 那么直接返回 obj.__dict__['attr'], 否则
(3)如果“attr”出现在Clz或其基类的__dict__中
(3.1)如果attr是non-data descriptor,那么调用其__get__方法, 否则
(3.2)返回 __dict__['attr']
(4)如果Clz有__getattr__方法,调用__getattr__方法,否则
(5)抛出AttributeError
下面是测试代码:
View Code
注意第50行,change_attr给实例的__dict__里面增加了两个属性。通过上下两条print的输出如下:
Derive object dict {'same_name_attr': 'attr in object', 'not_des_attr': 'I am not descriptor attr'}
Derive object dict {'same_name_attr': 'attr in object', 'ndd_derive': 'ndd_derive now in object dict ', 'not_des_attr': 'I am not descriptor attr', 'dd_base': 'dd_base now in object dict '}
调用change_attr方法之后,dd_base既出现在类的__dict__(作为data descriptor), 也出现在实例的__dict__, 新航道雅思培训因为attribute lookup的循序,所以优先返回的还是Clz.__dict__['dd_base']。而ndd_base虽然出现在类的__dict__, 但是因为是nondata descriptor,所以优先返回obj.__dict__['dd_base']。其他:line48,line56表明了__getattr__的作用。line49表明obj.__dict__优先于Clz.__dict__
前面提到过,类的也是对象,类是元类(metaclass)的实例,所以类属性的查找顺序基本同上,区别在于第二步,由于Clz可能有基类,所以是在Clz及其基类的__dict__查找“attr"
文末,我们再来看一下这段代码。
1 import functools, time 2 class cached_property(object): 3 """ A property that is only computed once per instance and then replaces 4 itself with an ordinary attribute. Deleting the attribute resets the 5 property. """ 6 7 def __init__(self, func): 8 functools.update_wrapper(self, func) 9 self.func = func10 11 def __get__(self, obj, cls):12 if obj is None: return self13 value = obj.__dict__[self.func.__name__] = self.func(obj)14 return value15 16 class TestClz(object):17 @cached_property18 def complex_calc(self):19 print 'very complex_calc'20 return sum(range(100))21 22 if __name__=='__main__':23 t = TestClz()24 print '>>> first call'25 print t.complex_calc26 print '>>> second call'27 print t.complex_calc
cached_property是一个non-data descriptor。在TestClz中,用cached_property装饰方法complex_calc,返回值是一个descriptor实例,所以在调用的时候没有使用小括号。
第一次调用t.complex_calc之前,obj(t)的__dict__中没有”complex_calc“, 根据查找顺序第三条,执行cached_property.__get__, 这个函数代用缓存的complex_calc函数计算出结果,并且把结果放入obj.__dict__。那么第二次访问t.complex_calc的时候,根据查找顺序,第二条有限于第三条,所以就直接返回obj.__dict__['complex_calc']。bottle的源码中还有两个descriptor,非常厉害!
转载于:https://blog.51cto.com/zhangtaoze/1913993
python属性查找 深入理解(attribute lookup)相关推荐
- python属性_深入理解python对象及属性
类属性和实例属性 首先来看看类属性和类实例的属性在python中如何存储,通过__dir__方法来查看对象的属性 >>> class Test(object): pass >& ...
- 非常易于理解‘类'与'对象’ 间 属性 引用关系,暨《Python 中的引用和类属性的初步理解》读后感...
关键字:名称,名称空间,引用,指针,指针类型的指针(即指向指针的指针) 我读完后的理解总结: 1. 我们知道,python中的变量的赋值操作,变量其实就是一个名称name,赋值就是将name引用到一个 ...
- python中的类实例的属性查找过程
__getattr__.__getattribute__对属性查找的影响 没有__getxxx__的例子 class Book:press = "人民邮电出版社"class Lan ...
- python 3爬虫学习笔记(2)—— 通过属性查找标签
一.关于层叠样式表(CSS) 层叠样式表(英文全称:Cascading Style Sheets)是一种用来表现HTML(标准通用标记语言的一个应用)或XML(标准通用标记语言的一个子集)等文件样式的 ...
- python面向编程:类继承、继承案例、单继承下属性查找、super方法
一.类的继承 二.基于继承解决类与类的代码冗余问题 三.在单继承背景下属性的查找 四.super的方法 一.类的继承 1.什么是继承? 在程序中继承是一种新建子类的方法的方式,新创建的类成为子类\派生 ...
- python属性和方法的区别_Python中几种属性访问的区别与用法详解
起步 在Python中,对于一个对象的属性访问,我们一般采用的是点(.)属性运算符进行操作.例如,有一个类实例对象foo,它有一个name属性,那便可以使用foo.name对此属性进行访问.一般而言, ...
- python属性访问顺序_Python 对象属性的访问
在 Python 中,一切皆对象.属性访问可以理解为是从一个已有的对象中获得另一个对象的方法.对象属性的访问涉及到对象的 __dict__ 属性.描述符等概念,以及 __getattribute__. ...
- python只读模式可以打印嘛_只读python属性?无法打印对象
在Python中,使用自定义描述符可以很容易地做到这一点.在 看看HOWTO中的Descriptor Example.如果您只需更改__get__方法来引发一个AttributeError就这样了.我 ...
- 面向对象:继承(经典类新式类继承原理、属性查找)、派生
继承: 继承是指类与类之间的关系,是一种"什么"是"什么"的关系. 继承的功能之一就是用来解决代码重用问题 继承是一种创建新类的方式,在Python中,新建的类 ...
最新文章
- java property异常_Java常见的异常和解决的办法
- c语言如何输出整串链表,大神帮我看一下怎么输入输出一个链表,我输入了但是没输出啊...
- 很用心的写了 9 道 MySQL 面试题
- 安装wamp时出现httpd.exe无法找到组件MSVCR100.dll的解决办法
- 由于开发者通过接口修改了菜单配置_Android SDK开发艺术探索(四)个性化配置...
- junit5和junit4_JUnit 5 –架构
- spark中dataframe解析_Spark-SQL
- Android 滑动菜单框架--SwipeMenuListView框架完全解析
- 关于CAS服务器磁盘占用的问题,锁定目录惹的祸
- numpy基础笔记02
- oracle 表收缩,Oracle 收缩表大小 Oracle Shrink Table
- VB.Net数据库编程
- AI 人工智能之概率论基础(概念总结和复习)
- 一文彻底搞懂激光雷达原理!
- PTA 乙级 【1007】素数对猜想
- 网络安全系列之三十七 Pangolin(穿山甲)和Havij(胡萝卜)的使用
- ROS使用yocs_smoother_velocity做速度平滑处理
- 什么是大数据分析 主要应用于哪些行业?
- 年底不要慌,这个EXCEL模板帮你打赢Q4收官战
- 有哪些好用的设备巡检类的软件?
热门文章
- mapbox 将坐标转换成米
- foreach+php+四维数组,怎么在PHP中利用foreach对多维数组进行遍历
- python界面颜色设置_pycharm修改界面主题颜色的方法
- python编程狮苹果系统_Python编程狮app下载-Python编程狮苹果版v1.0
- Query 中使用 text() 或者 html() 函数可bai以获取font or td 的内容:
- murmurhash java_浅析ketamahash和murmurhash
- 电脑开机卡住了怎么办_苹果电脑忘记开机密码怎么办?一段代码轻松解决
- php spl自动加载类,php – SPL自动加载最佳实践
- 光复用技术中三种重要技术_【技术文章】X射线无损检测仪在锂电池行业中的重要应用...
- python元组是有序还是无序_python-03 元组和字典