前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >深入理解 Python 的属性查找

深入理解 Python 的属性查找

作者头像
企鹅号小编
发布2018-02-09 10:32:01
9610
发布2018-02-09 10:32:01
举报
文章被收录于专栏:编程

今天我们了解下python的属性查找,在Python中,属性查找(attribute lookup)是比较复杂的,特别是涉及到描述符descriptor的时候。 首先,我们知道: python中一切都是对象,“everything is object”,包括类,类的实例,数字,模块 任何object都是类(class or type)的实例(instance) 如果一个descriptor只实现了get方法,我们称之为non-data descriptor, 如果同时实现了get

__set__

我们称之为data descriptor。

实例属性查找

按照python doc,如果obj是某个类的实例,那么obj.name(以及等价的getattr(obj,’name’))首先调用getattribute。如果类定义了getattr方法,那么在getattribute抛出 AttributeError 的时候就会调用到getattr,而对于描述符(

__get__

)的调用,则是发生在getattribute内部的。官网文档是这么描述的

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

下面是测试代码:

调用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__

cached_property例子

我们再来看看上一文章的这段代码

Widget是一个之定义了一个func函数的类,func是类的属性,这个也可以通过Widget.dict、w.dict看到。Widget.dict[‘func’]返回的是一个function,但Widget.func是一个unbound method,即Widget.func并不等同于Widget.dict[‘func’],按照前面的类属性的访问顺序,我们可以怀疑,func是一个descriptor,这样才不会走到第2.2这种情况。验证如下:

可以看到,即使Widget的实例也有一个‘a’属性,但是调用w.a的时候会调用类属性‘a’(一个descriptor)的set方法。如果不注释掉第18到第20行,输出如下

可以看到,优先调用Widget 的setattr方法。因此:对于属性赋值,obj = Clz(), 那么obj.attr = var,按照这样的顺序:

如果Clz定义了setattr方法,那么调用该方法,否则 如果“attr”是出现在Clz或其基类的dict中, 且attr是data descriptor, 那么调用其set方法, 否则 等价调用obj.dict[‘attr’] = var

本文来自企鹅号 - 育人不予媒体

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文来自企鹅号 - 育人不予媒体

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档