python3.6 源码分析(一)
来源:互联网 发布:ohem算法 编辑:程序博客网 时间:2024/06/06 08:31
从字节码入手
a = 1
编译:
LOAD_CONST 0 (1)STORE_NAME 0 (a)
根据官方文档的字节码解释:
LOAD_CONST从codeobject的co_consts这个列表中读取对应索引的值到栈顶,这里是列表的第0个元素,值为longobject(1)
STORE_NAME将栈顶元素绑定到codeobject的co_names这个列表的第i个元素,这里i是0,也就是stringobject(‘a’)
这时我有一个问题:STORE_NAME后是否弹出了栈顶元素?
在ceval中找到对应代码:
TARGET(STORE_NAME) { PyObject *name = GETITEM(names, oparg); PyObject *v = POP(); PyObject *ns = f->f_locals; int err; if (ns == NULL) { PyErr_Format(PyExc_SystemError, "no locals found when storing %R", name); Py_DECREF(v); goto error; } if (PyDict_CheckExact(ns)) err = PyDict_SetItem(ns, name, v); else err = PyObject_SetItem(ns, name, v); Py_DECREF(v); if (err != 0) goto error; DISPATCH(); }
看看TARGET这个宏:
#define TARGET(op) \ case op:
好吧,其实就是一个case。
让我们看一下STORE_NAME做了些啥:
1. 首先获取到要保存的名字
2. 获取要保存的栈顶变量
注意,这里用了POP,猜都能猜到,栈顶已经被删除了。。。。。答案已经找到了,但是我想继续看看后面怎么做
3. 栈帧的locals,也就是局部变量,保存到ns
4. 然后检测ns是否是一个字典,如果是就当作字典,否则就当做一般对象,将名字和对应的值保存到当前栈帧的f_locals,完事!
这里:
if (PyDict_CheckExact(ns)) err = PyDict_SetItem(ns, name, v); else err = PyObject_SetItem(ns, name, v);
一般对象的setitem和字典对象的setitem引起了我的兴趣,我决定一探究竟,看看他们有什么区别
首先看PyDict_SetItem:
intPyDict_SetItem(PyObject *op, PyObject *key, PyObject *value){ PyDictObject *mp; Py_hash_t hash; if (!PyDict_Check(op)) { PyErr_BadInternalCall(); return -1; } assert(key); assert(value); mp = (PyDictObject *)op; if (!PyUnicode_CheckExact(key) || (hash = ((PyASCIIObject *) key)->hash) == -1) { hash = PyObject_Hash(key); if (hash == -1) return -1; } /* insertdict() handles any resizing that might be necessary */ return insertdict(mp, key, hash, value);}
不得不说看python源码就跟看小说一样,一眼就能看清代码的意图,你看一进来先是三个参数的检查,然后计算key的hash值,然后把dict,key,hash,value传给insertdict去进行最后的插入操作,下一步就不去跟进了,要看了字典的具体实现才能理解,毕竟python3.4以后字典做了较大的改动,比较麻烦。
回过头来,再看看PyObject_SetItem的实现:
intPyObject_SetItem(PyObject *o, PyObject *key, PyObject *value){ PyMappingMethods *m; if (o == NULL || key == NULL || value == NULL) { null_error(); return -1; } m = o->ob_type->tp_as_mapping; if (m && m->mp_ass_subscript) return m->mp_ass_subscript(o, key, value); if (o->ob_type->tp_as_sequence) { if (PyIndex_Check(key)) { Py_ssize_t key_value; key_value = PyNumber_AsSsize_t(key, PyExc_IndexError); if (key_value == -1 && PyErr_Occurred()) return -1; return PySequence_SetItem(o, key_value, value); } else if (o->ob_type->tp_as_sequence->sq_ass_item) { type_error("sequence index must be " "integer, not '%.200s'", key); return -1; } } type_error("'%.200s' object does not support item assignment", o); return -1;}
其中有几个不知道是干嘛的方法
mp_ass_subscript
PySequence_SetItem
不过可以猜到,前者是字典的setitem,而后者是序列对象的setitem,key必须是Py_ssize_t。
源码分析任重而道远,本篇只是一个开头
- python3.6 源码分析(一)
- python3.6 源码分析(二):另一个例子
- python3.6 源码分析(四):函数调用
- python3.6 源码分析(三):创建函数
- python3.6 源码分析(五):类的创建
- 源码分析(一)
- JUnit源码分析(一)
- osworkflow源码分析(一)
- Log4net源码分析(一)
- Mangos源码分析(一)
- Notepad++源码分析(一)
- Log4net源码分析(一)
- ConcurrentHashMap 源码分析 (一)
- rabbitmq源码分析(一)
- rabbitmq源码分析(一)
- Notepad++源码分析(一)
- ADB源码分析(一)
- Tomcat源码分析(一)
- 使用 npm install 安装的node-ffmpeg不是最新版本的问题
- [Object-C]_[C/C++]_[日期时间操作对比]
- Docker实战:mysql主从备份读写分离
- get_env
- ios-应用程序跳转到指定的页面
- python3.6 源码分析(一)
- 迭代求根
- Okhttp封装包
- C# 中的 is 和 as
- 欢迎使用CSDN-markdown编辑器
- 线段树浅谈
- 死锁、饥饿、活锁、wait()、notifyAll()、notify()
- mybatis调用存储过程(plsql)
- 8.2.1.19 防止全表扫描