类的 __dict__

先看一个例子:

> class A(object): pass
> ...
> A.__dict__
dict_proxy({'__dict__': <attribute '__dict__' of 'A' objects>, '__module__': '__main__', '__weakref__': <attribute '__weakref__' of 'A' objects>, '__doc__': None})

发现 dict 是一个 dict_proxy 类型,为何不是一个简单的 python dict 呢?跟一下代码看一下:

case LOAD_ATTR:
   w = GETITEM(names, oparg);
   v = TOP();
   x = PyObject_GetAttr(v, w);
   Py_DECREF(v);
   SET_TOP(x);
   if (x != NULL) continue;
   break;

获取变量会执行 LOAD_ATTR 的机器码,对于 A 类会走到如下函数:

# in typeobject.c
static PyObject *
type_getattro(PyTypeObject *type, PyObject *name) {
   ...
   meta_attribute = _PyType_Lookup(metatype, name);  【1】
   if (meta_attribute != NULL) {
   meta_get = Py_TYPE(meta_attribute)->tp_descr_get;

   if (meta_get != NULL && PyDescr_IsData(meta_attribute)) {
       /* Data descriptors implement tp_descr_set to intercept
        * writes. Assume the attribute is not overridden in
        * type's tp_dict (and bases): call the descriptor now.
        */
       return meta_get(meta_attribute, (PyObject *)type,
                       (PyObject *)metatype);   【2】
   }

}

元类型:对于一个类的元类型是类型,对于类,会在类型中寻找 __dict __(参考1),返回一个描述符,并调用描述符 get 函数(参考2)。

最终会运行到下面的代码:

# in typeobject.c
static PyObject *
type_dict(PyTypeObject *type, void *context)
{
   if (type->tp_dict == NULL) {
       Py_INCREF(Py_None);
       return Py_None;
   }
   return PyDictProxy_New(type->tp_dict); 【1】
}

【1】这里类型就是 A 类,所有就是读取 A 类的 tp_dict

 实例的__dict__

读取一个类的实例的 __dict__ 会调用到如下方法:

# in object.c
PyObject *
_PyObject_GenericGetAttrWithDict(PyObject *obj, PyObject *name, PyObject *dict) {
   ....
   descr = _PyType_Lookup(tp, name);   【1】

}

这里 tp 就是 A 类,因此我们需要在 A 类的 tp dict 寻找 \ _dict__ 变量,ok,使用下面的方式看一下:

> A.__dict__["__dict__"]
<attribute '__dict__' of 'A' objects>
> type(A.__dict__["__dict__"])
<type 'getset_descriptor'>

这样会调用到对应的描述符

# in typeobject.c
static PyObject *
subtype_dict(PyObject *obj, void *context) {
   ....
   dictptr = _PyObject_GetDictPtr(obj);
   ....
   dict = *dictptr;
   ....
   return dict;
}

上面的 obj 就是 A 类的实例。

模块的__dict__

模块的基本逻辑与实例相似,也是调用 _PyObject_GenericGetAttrWithDict 方法。

> type(a_p).__dict__['__dict__']
<member '__dict__' of 'module' objects>
> type(type(a_p).__dict__['__dict__'])
<type 'member_descriptor'>

会拿到模块的 __dict__,然后调用描述符对应的获取函数。

# in structmember.c
PyObject *
PyMember_GetOne(const char *addr, PyMemberDef *l)
....

作者:Whosemario

原文链接:http://t.cn/RgcAB5Y

浅谈__dict__的更多相关文章

  1. python进阶_浅谈面向对象进阶

    python进阶_浅谈面向对象进阶 学了面向对象三大特性继承,多态,封装.今天我们看看面向对象的一些进阶内容,反射和一些类的内置函数. 一.isinstance和issubclass  class F ...

  2. 浅谈 Fragment 生命周期

    版权声明:本文为博主原创文章,未经博主允许不得转载. 微博:厉圣杰 源码:AndroidDemo/Fragment 文中如有纰漏,欢迎大家留言指出. Fragment 是在 Android 3.0 中 ...

  3. 浅谈 LayoutInflater

    浅谈 LayoutInflater 版权声明:本文为博主原创文章,未经博主允许不得转载. 微博:厉圣杰 源码:AndroidDemo/View 文中如有纰漏,欢迎大家留言指出. 在 Android 的 ...

  4. 浅谈Java的throw与throws

    转载:http://blog.csdn.net/luoweifu/article/details/10721543 我进行了一些加工,不是本人原创但比原博主要更完善~ 浅谈Java异常 以前虽然知道一 ...

  5. 浅谈SQL注入风险 - 一个Login拿下Server

    前两天,带着学生们学习了简单的ASP.NET MVC,通过ADO.NET方式连接数据库,实现增删改查. 可能有一部分学生提前预习过,在我写登录SQL的时候,他们鄙视我说:“老师你这SQL有注入,随便都 ...

  6. 浅谈WebService的版本兼容性设计

    在现在大型的项目或者软件开发中,一般都会有很多种终端, PC端比如Winform.WebForm,移动端,比如各种Native客户端(iOS, Android, WP),Html5等,我们要满足以上所 ...

  7. 浅谈angular2+ionic2

    浅谈angular2+ionic2   前言: 不要用angular的语法去写angular2,有人说二者就像Java和JavaScript的区别.   1. 项目所用:angular2+ionic2 ...

  8. iOS开发之浅谈MVVM的架构设计与团队协作

    今天写这篇博客是想达到抛砖引玉的作用,想与大家交流一下思想,相互学习,博文中有不足之处还望大家批评指正.本篇博客的内容沿袭以往博客的风格,也是以干货为主,偶尔扯扯咸蛋(哈哈~不好好工作又开始发表博客啦 ...

  9. Linux特殊符号浅谈

    Linux特殊字符浅谈 我们经常跟键盘上面那些特殊符号比如(?.!.~...)打交道,其实在Linux有其独特的含义,大致可以分为三类:Linux特殊符号.通配符.正则表达式. Linux特殊符号又可 ...

随机推荐

  1. Linux uname命令详解

    uname常见命令参数 -a, --all print all information, in the following order, except omit -p and -i if unknow ...

  2. PHP解决网站大数据大流量与高并发

    1:硬件方面 普通的一个p4的服务器每天最多能支持10万左右的IP,如果访问量超过10W那么需要专用的服务器才能解决,如果硬件不给力软件怎么优化都是于事无补的.主要影响服务器的速度 有:网络-硬盘读写 ...

  3. Ubuntn系统(虚拟机)忘记密码的解决方法

    1.重启ubuntu系统,开机时长按shift按键进入GRUB菜单,选择第二个高级选项,enter键进入.如下图: 2.在高级选择中选择Recovery mode模式,键盘按“e”键进入编辑模式.如下 ...

  4. November 28th 2016 Week 49th Monday

    You only live once, but if you do it right, once is enough. 年华不虚度,一生也足矣. One today can win two tomor ...

  5. JDK源码学习LinkedList

    LinkedList是List接口的子类,它底层数据结构是双向循环链表.LinkedList还实现了Deque接口(double-end-queue双端队列,线性collection,支持在两端插入和 ...

  6. 1503. [NOI2004]郁闷的出纳员【平衡树-splay】

    Description OIER公司是一家大型专业化软件公司,有着数以万计的员工.作为一名出纳员,我的任务之一便是统计每位员工的 工资.这本来是一份不错的工作,但是令人郁闷的是,我们的老板反复无常,经 ...

  7. P4053 [JSOI2007]建筑抢修

    题目描述 小刚在玩JSOI提供的一个称之为“建筑抢修”的电脑游戏:经过了一场激烈的战斗,T部落消灭了所有z部落的入侵者.但是T部落的基地里已经有N个建筑设施受到了严重的损伤,如果不尽快修复的话,这些建 ...

  8. Python自动化之高级语法单例模式

    方法1 共享属性;所谓单例就是所有引用(实例.对象)拥有相同的状态(属性)和行为(方法) 同一个类的所有实例天然拥有相同的行为(方法), 只需要保证同一个类的所有实例具有相同的状态(属性)即可 所有实 ...

  9. servlet使用

    一.使用IDEAL创建项目 1) 2) 3) 4) 5) 6) 7) 8) 9) 二.路径介绍: 配置文件: servlet配置文件: package ser_Test; import javax.s ...

  10. 命令行编译执行java

    命令行编译运行java程序 使用命令 javac进行编译 和 java进行执行. javac 后面跟着的是java文件的文件名,例如 HelloWorld.java. 该命令用于将 java 源文件编 ...