#import.c #define MAGIC (62211 | ((long)'\r'<<16) | ((long)'\n'<<24)) static void write_compiled_module(PyCodeObject *co, char *cpathname, struct stat *srcstat, time_t mtime) { FILE *fp; #排他性的打开文件 #ifdef MS_WINDOWS /* since Windows uses different permissions */ mode_t mode = srcstat->st_mode & ~S_IEXEC; /* Issue #6074: We ensure user write access, so we can delete it later * when the source file changes. (On POSIX, this only requires write * access to the directory, on Windows, we need write access to the file * as well) */ mode |= _S_IWRITE; #else mode_t mode = srcstat->st_mode & ~S_IXUSR & ~S_IXGRP & ~S_IXOTH; #endif
#frameobject.h typedef struct _frame { PyObject_VAR_HEAD #变长对象, 不同PyCodeObject, 栈空间大小不同 struct _frame *f_back; /* previous frame, or NULL 执行环境链上的前一个frame*/ PyCodeObject *f_code; /* code segment PyCodeObject对象*/ PyObject *f_builtins; /* builtin symbol table (PyDictObject) buildin名字空间*/ PyObject *f_globals; /* global symbol table (PyDictObject) global名字空间*/ PyObject *f_locals; /* local symbol table (any mapping) local名字空间*/ PyObject **f_valuestack; /* points after the last local 运行时栈的栈底位置*/ /* Next free slot in f_valuestack. Frame creation sets to f_valuestack. Frame evaluation usually NULLs it, but a frame that yields sets it to the current stack top. */ PyObject **f_stacktop; #运行时栈的栈底位置 PyObject *f_trace; /* Trace function */
/* If an exception is raised in this frame, the next three are used to * record the exception info (ifany) originally in the thread state. See * comments before set_exc_info() -- it's not obvious. * Invariant: if _type is NULL, then so are _value and _traceback. * Desired invariant: all three are NULL, or all three are non-NULL. That * one isn't currently true, but "should be". */ PyObject *f_exc_type, *f_exc_value, *f_exc_traceback;
PyThreadState *f_tstate; int f_lasti; /* Last instruction if called 上一条字节码指令在f_code中的偏移位置*/ /* Call PyFrame_GetLineNumber() instead of reading this field directly. As of 2.3 f_lineno is only valid when tracing is active (i.e. when f_trace isset). At other times we use PyCode_Addr2Line to calculate the line from the current bytecode index. */ int f_lineno; /* Current line number 当前字节码对应的源代码行*/ int f_iblock; /* index in f_blockstack */ PyTryBlock f_blockstack[CO_MAXBLOCKS]; /* fortryand loop blocks */ PyObject *f_localsplus[1]; /* locals+stack, dynamically sized 动态内存,维护(局部变量+cell对象集合+free对象集合+运行时栈)所需要的空间*/ } PyFrameObject;
#ifdef HAVE_DLOPEN int dlopenflags; #endif #ifdef WITH_TSC int tscdump; #endif
} PyInterpreterState;
typedef struct _ts { /* See Python/ceval.c for comments explaining most fields */
struct _ts *next; PyInterpreterState *interp;
struct _frame *frame; #模拟线程中的函数调用堆栈, PyFrameObject对象 int recursion_depth; /* 'tracing' keeps track of the execution depth when tracing/profiling. This is to prevent the actual trace/profile code from being recorded in the trace/profile. */ int tracing; int use_tracing;
/* tick_counter is incremented whenever the check_interval ticker * reaches zero. The purpose is to give a useful measure of the number * of interpreted bytecode instructions in a given thread. This * extremely lightweight statistic collector may be of interest to * profilers (like psyco.jit()), although nothing in the core uses it. */ int tick_counter;
int gilstate_counter;
PyObject *async_exc; /* Asynchronous exception to raise */ long thread_id; /* Thread id where this tstate was created */
int trash_delete_nesting; PyObject *trash_delete_later;
#funcobject.h typedef struct { PyObject_HEAD PyObject *func_code; /* A code object 函数编译后的PyCodeObject对象*/ PyObject *func_globals; /* A dictionary (other mappings won't do) 函数运行时global名字空间*/ PyObject *func_defaults; /* NULL or a tuple 默认参数*/ PyObject *func_closure; /* NULL or a tuple of cell objects 闭包的实现*/ PyObject *func_doc; /* The __doc__ attribute, can be anything 函数文档*/ PyObject *func_name; /* The __name__ attribute, a string object 函数名称*/ PyObject *func_dict; /* The __dict__ attribute, a dict or NULL 函数的__dict__*/ PyObject *func_weakreflist; /* List of weak references */ PyObject *func_module; /* The __module__ attribute, can be anything */ /* Invariant: * func_closure contains the bindings for func_code->co_freevars, so * PyTuple_Size(func_closure) == PyCode_GetNumFree(func_code) * (func_closure may be NULL if PyCode_GetNumFree(func_code) == 0). */ } PyFunctionObject;
#ceval.c static PyObject * call_function(PyObject ***pp_stack, int oparg #ifdef WITH_TSC , uint64* pintr0, uint64* pintr1 #endif ) { #1. 处理函数参数信息 int na = oparg & 0xff; #oparg记录了参数的个数, na是位置参数的个数 int nk = (oparg>>8) & 0xff; #nk是键参数的个数 int n = na + 2 * nk; #2. 获得PyFunctionObject对象 PyObject **pfunc = (*pp_stack) - n - 1; PyObject *func = *pfunc; PyObject *x, *w;
/* Always dispatch PyCFunction first, because these are presumed to be the most frequent callableobject. */ if (PyCFunction_Check(func) && nk == 0) { ... #3. 调用PyFunctionObject对象 if (PyFunction_Check(func)) x = fast_function(func, pp_stack, n, na, nk); #一般函数通道和快速通道(通过参数形式来确定是否进入快速通道) else x = do_call(func, pp_stack, na, nk); READ_TIMESTAMP(*pintr1); Py_DECREF(func); }
/* Clear the stack of the function object. Also removes the arguments incase they weren't consumed already (fast_function() and err_args() leave them on the stack). */ while ((*pp_stack) > pfunc) { w = EXT_POP(*pp_stack); Py_DECREF(w); PCALL(PCALL_POP); } return x; }
#ifdef Py_TRACE_REFS /* PyType_Ready is the closest thing we have to a choke point * fortype objects, so is the best place I can think of to try * to get type objects into the doubly-linked list of all objects. * Still, notalltype objects go thru PyType_Ready. */ _Py_AddToAllObjects((PyObject *)type, 0); #endif
/* Initialize tp_base (defaults to BaseObject unless that's us) 尝试获得type的tp_base中指定的基类 class对象都是直接或者间接以PyBaseObject_Type(object)为基类 */ base = type->tp_base; if (base == NULL && type != &PyBaseObject_Type) { base = type->tp_base = &PyBaseObject_Type; Py_INCREF(base); } /* Now the only way base can still be NULL is if type is * &PyBaseObject_Type. */ /* Initialize the base class 如果基类没有初始化, 先初始化基类*/ if (base && base->tp_dict == NULL) { if (PyType_Ready(base) < 0) goto error; } /* Initialize ob_type if NULL. This means extensions that want to be compilable separately on Windows can call PyType_Ready() instead of initializing the ob_type field of their type objects. */ /* The test for base != NULL is really unnecessary, since base is only NULL when type is &PyBaseObject_Type, and we know its ob_type is not NULL (it's initialized to &PyType_Type). But coverity doesn't know that. 设置基类信息*/ if (Py_TYPE(type) == NULL && base != NULL) Py_TYPE(type) = Py_TYPE(base); ... }
obj = type->tp_new(type, args, kwds); if (obj != NULL) { /* Ugly exception: when the call was type(something), don't call tp_init on the result. */ if (type == &PyType_Type && PyTuple_Check(args) && PyTuple_GET_SIZE(args) == 1 && (kwds == NULL || (PyDict_Check(kwds) && PyDict_Size(kwds) == 0))) return obj; /* If the returned object is not an instance of type, it won't be initialized. */ if (!PyType_IsSubtype(obj->ob_type, type)) return obj; type = obj->ob_type; if (PyType_HasFeature(type, Py_TPFLAGS_HAVE_CLASS) && type->tp_init != NULL && type->tp_init(obj, args, kwds) < 0) { Py_DECREF(obj); obj = NULL; } } return obj; }
if (!PyString_Check(name)) { #ifdef Py_USING_UNICODE /* The Unicode to string conversion is done here because the existing tp_getattro slots expect a string objectas name and we wouldn't want to break those. */ if (PyUnicode_Check(name)) { name = _PyUnicode_AsDefaultEncodedString(name, NULL); if (name == NULL) return NULL; } else #endif { PyErr_Format(PyExc_TypeError, "attribute name must be string, not '%.200s'", Py_TYPE(name)->tp_name); return NULL; } } #1. 通过tp_getattro获得属性对应对象 if (tp->tp_getattro != NULL) return (*tp->tp_getattro)(v, name); #2. 通过tp_getattr获得属性对应对象 if (tp->tp_getattr != NULL) return (*tp->tp_getattr)(v, PyString_AS_STRING(name)); #3. 属性不存在,抛出异常 PyErr_Format(PyExc_AttributeError, "'%.50s' object has no attribute '%.400s'", tp->tp_name, PyString_AS_STRING(name)); return NULL; }