在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)相关推荐

  1. python属性_深入理解python对象及属性

    类属性和实例属性 首先来看看类属性和类实例的属性在python中如何存储,通过__dir__方法来查看对象的属性 >>> class Test(object): pass >& ...

  2. 非常易于理解‘类'与'对象’ 间 属性 引用关系,暨《Python 中的引用和类属性的初步理解》读后感...

    关键字:名称,名称空间,引用,指针,指针类型的指针(即指向指针的指针) 我读完后的理解总结: 1. 我们知道,python中的变量的赋值操作,变量其实就是一个名称name,赋值就是将name引用到一个 ...

  3. python中的类实例的属性查找过程

    __getattr__.__getattribute__对属性查找的影响 没有__getxxx__的例子 class Book:press = "人民邮电出版社"class Lan ...

  4. python 3爬虫学习笔记(2)—— 通过属性查找标签

    一.关于层叠样式表(CSS) 层叠样式表(英文全称:Cascading Style Sheets)是一种用来表现HTML(标准通用标记语言的一个应用)或XML(标准通用标记语言的一个子集)等文件样式的 ...

  5. python面向编程:类继承、继承案例、单继承下属性查找、super方法

    一.类的继承 二.基于继承解决类与类的代码冗余问题 三.在单继承背景下属性的查找 四.super的方法 一.类的继承 1.什么是继承? 在程序中继承是一种新建子类的方法的方式,新创建的类成为子类\派生 ...

  6. python属性和方法的区别_Python中几种属性访问的区别与用法详解

    起步 在Python中,对于一个对象的属性访问,我们一般采用的是点(.)属性运算符进行操作.例如,有一个类实例对象foo,它有一个name属性,那便可以使用foo.name对此属性进行访问.一般而言, ...

  7. python属性访问顺序_Python 对象属性的访问

    在 Python 中,一切皆对象.属性访问可以理解为是从一个已有的对象中获得另一个对象的方法.对象属性的访问涉及到对象的 __dict__ 属性.描述符等概念,以及 __getattribute__. ...

  8. python只读模式可以打印嘛_只读python属性?无法打印对象

    在Python中,使用自定义描述符可以很容易地做到这一点.在 看看HOWTO中的Descriptor Example.如果您只需更改__get__方法来引发一个AttributeError就这样了.我 ...

  9. 面向对象:继承(经典类新式类继承原理、属性查找)、派生

    继承: 继承是指类与类之间的关系,是一种"什么"是"什么"的关系. 继承的功能之一就是用来解决代码重用问题 继承是一种创建新类的方式,在Python中,新建的类 ...

最新文章

  1. java property异常_Java常见的异常和解决的办法
  2. c语言如何输出整串链表,大神帮我看一下怎么输入输出一个链表,我输入了但是没输出啊...
  3. 很用心的写了 9 道 MySQL 面试题
  4. 安装wamp时出现httpd.exe无法找到组件MSVCR100.dll的解决办法
  5. 由于开发者通过接口修改了菜单配置_Android SDK开发艺术探索(四)个性化配置...
  6. junit5和junit4_JUnit 5 –架构
  7. spark中dataframe解析_Spark-SQL
  8. Android 滑动菜单框架--SwipeMenuListView框架完全解析
  9. 关于CAS服务器磁盘占用的问题,锁定目录惹的祸
  10. numpy基础笔记02
  11. oracle 表收缩,Oracle 收缩表大小 Oracle Shrink Table
  12. VB.Net数据库编程
  13. AI 人工智能之概率论基础(概念总结和复习)
  14. 一文彻底搞懂激光雷达原理!
  15. PTA 乙级 【1007】素数对猜想
  16. 网络安全系列之三十七 Pangolin(穿山甲)和Havij(胡萝卜)的使用
  17. ROS使用yocs_smoother_velocity做速度平滑处理
  18. 什么是大数据分析 主要应用于哪些行业?
  19. 年底不要慌,这个EXCEL模板帮你打赢Q4收官战
  20. 有哪些好用的设备巡检类的软件?

热门文章

  1. mapbox 将坐标转换成米
  2. foreach+php+四维数组,怎么在PHP中利用foreach对多维数组进行遍历
  3. python界面颜色设置_pycharm修改界面主题颜色的方法
  4. python编程狮苹果系统_Python编程狮app下载-Python编程狮苹果版v1.0
  5. Query 中使用 text() 或者 html() 函数可bai以获取font or td 的内容:
  6. murmurhash java_浅析ketamahash和murmurhash
  7. 电脑开机卡住了怎么办_苹果电脑忘记开机密码怎么办?一段代码轻松解决
  8. php spl自动加载类,php – SPL自动加载最佳实践
  9. 光复用技术中三种重要技术_【技术文章】X射线无损检测仪在锂电池行业中的重要应用...
  10. python元组是有序还是无序_python-03 元组和字典