虽然自己会吐槽python这语言让人受不了的慢,不过也不得不说python语言在语法上的精炼,在写代码的时候确实会比java方便一些。。。不过由于python无法像java一样项目的开始先定义一套强类型限制的接口,所以总感觉在写python的时候有点不踏实。。。不过pycharm从某种程度上通过注释也能减轻一点这方面的担忧。。
好了。。。。。决定了要看一下python的实现。。。这里就先从python的对象结构来说吧。。。。
在python中,所有的东西都是对象,整数是,方法也是,。。总之什么都是。。。。
在看python的代码实现中,可以随处看到指针类型:PyObject*,那么我们就先来看看PyObject这到底是怎么定义的吧:
typedef struct _object { //这个是所有python对象的基础,这个是不可变对象
PyObject_HEAD
} PyObject;
他就是整个python环境中最上层的对象结构,很简单,就包括一个对象头部,那么来看看它的定义:
//通过这个结构,将所有对象构成一个双链表
/* Define pointers to support a doubly-linked list of all live heap objects. */
#define _PyObject_HEAD_EXTRA \
struct _object *_ob_next; \
struct _object *_ob_prev;
#define _PyObject_EXTRA_INIT 0, 0,
#else
#define _PyObject_HEAD_EXTRA
#define _PyObject_EXTRA_INIT
#endif
//所有对象共有的数据,这个放在所有对象内存的最开始部分,首先是构成对象链表的前后执指针,其次是引用数量,以及它的类型对象
/**
(1)前后指针,构成循环链表
(2)引用计数
(3)类型对象
**/
/* PyObject_HEAD defines the initial segment of every PyObject. */
#define PyObject_HEAD \
_PyObject_HEAD_EXTRA \
Py_ssize_t ob_refcnt; \
struct _typeobject *ob_type;
可以看出,头部由3部分来构成,首先是一个前后指针,用于将对象构成一个双向的链表,其次就是比较重要的引用计数了。。。然后还有就是类型对象----》每一个对象都有一个指针指向其所指向的类型对象。。。
既然看到了引用计数,那么就来说说python的GC吧。。。它跟java在GC最大的不同点就是有一套基于引用计数的内存回收。。。
(1)每一个对象都关联一个引用计数,当这个计数为0的时候,那么它的内存就可以被回收了
(2)对于有循环引用的情况,python也有一套可达性分析的gc来回收内存。。当然它这部分就比java简单的多了
上面看的时最基础的PyObject结构。。。另外这里还有另外一种结构:PyVarObject,它用于指代一些变长对象,主要是一些容器。。。。
//一般都是一些容器啥的
typedef struct { //可变对象的基础
PyObject_VAR_HEAD
} PyVarObject;
//即使是可变对象,首先也是有一个统一的对象头部,ob_size一般用于记录容器中数据项个数,注意这里不是字节数
#define PyObject_VAR_HEAD \
PyObject_HEAD \
Py_ssize_t ob_size; /* Number of items in variable part */
#define Py_INVALID_SIZE (Py_ssize_t)-1
它其实也就是扩展了一个0b_size字段。。。本质上也是与PyObject统一的。。。。所以对于PyVarObject,也可以用PyObject指针来引用。。从而达到了统一。。。。
通过上面的内容,我们知道,所有的对象,都会有一个ob_type指针域,用于指向当前对象的类型对象,那么接下来来看看类型对象的定义:
//这个用来指定一个对象的类型对象
typedef struct _typeobject {
PyObject_VAR_HEAD //这里有一个变长对象头部
const char *tp_name; /* For printing, in format "<module>.<name>" */ //用于打印当前类型的信息
Py_ssize_t tp_basicsize, tp_itemsize; /* For allocation */ //用于分配的大小
/* Methods to implement standard operations */
//下面是标准方法的定义
destructor tp_dealloc; //析构当前对象
printfunc tp_print; //在调用print打印类型的时候,将会调用这里来进行输出
getattrfunc tp_getattr; //getter函数
setattrfunc tp_setattr; //setter函数
cmpfunc tp_compare; //比较函数
reprfunc tp_repr; //转化为字符串
/* Method suites for standard classes */
PyNumberMethods *tp_as_number; //最为数字的进行操作的函数
PySequenceMethods *tp_as_sequence; //作为序列进行操作的函数
PyMappingMethods *tp_as_mapping; //作为字典进行操作的函数
/* More standard operations (here for binary compatibility) */
hashfunc tp_hash; //获取hash值的函数
ternaryfunc tp_call; //作为方法进行调用的时候
reprfunc tp_str;
getattrofunc tp_getattro;
setattrofunc tp_setattro;
/* Functions to access object as input/output buffer */
PyBufferProcs *tp_as_buffer; //将当前对象作为buffer进行处理的时候的方法
/* Flags to define presence of optional/expanded features */
long tp_flags;
const char *tp_doc; /* Documentation string */ //当前类型的文档
/* Assigned meaning in release 2.0 */
/* call function for all accessible objects */
traverseproc tp_traverse;
/* delete references to contained objects */
inquiry tp_clear;
/* Assigned meaning in release 2.1 */
/* rich comparisons */
richcmpfunc tp_richcompare;
/* weak reference enabler */
Py_ssize_t tp_weaklistoffset;
/* Added in release 2.2 */
/* Iterators */
getiterfunc tp_iter;
iternextfunc tp_iternext;
/* Attribute descriptor and subclassing stuff */
struct PyMethodDef *tp_methods; //方法
struct PyMemberDef *tp_members; //成员属性
struct PyGetSetDef *tp_getset;
struct _typeobject *tp_base; //父类型
PyObject *tp_dict;
descrgetfunc tp_descr_get;
descrsetfunc tp_descr_set;
Py_ssize_t tp_dictoffset;
initproc tp_init;
allocfunc tp_alloc;
newfunc tp_new;
freefunc tp_free; /* Low-level free-memory routine */
inquiry tp_is_gc; /* For PyObject_IS_GC */
PyObject *tp_bases;
PyObject *tp_mro; /* method resolution order */
PyObject *tp_cache;
PyObject *tp_subclasses;
PyObject *tp_weaklist;
destructor tp_del;
/* Type attribute cache version tag. Added in version 2.6 */
unsigned int tp_version_tag;
#ifdef COUNT_ALLOCS
/* these must be last and never explicitly initialized */
Py_ssize_t tp_allocs;
Py_ssize_t tp_frees;
Py_ssize_t tp_maxalloc;
struct _typeobject *tp_prev;
struct _typeobject *tp_next;
#endif
} PyTypeObject;
可以看到,这里主要是定义了很多公共的函数。。。。同时这里可以看到最开始他也定义了一个变长对象的头部PyObject_VAR_HEAD
那么也就是说,类型对象本身也是一个对象,也可以用PyObject指针来引用。。。。
嗯。。那么。。这里问题就来了。。。。既然类型对象也是一个对象。。。。那么类型对象他自己的类型对象是啥呢。。。?
嗯。。。在python中定义了一个最顶层的类型对象。。。。。
//最顶层的类型对象,它进行一个类型对象的自引用
PyTypeObject PyType_Type = {
PyVarObject_HEAD_INIT(&PyType_Type, 0)
"type", /* tp_name */
sizeof(PyHeapTypeObject), /* tp_basicsize */
sizeof(PyMemberDef), /* tp_itemsize */
(destructor)type_dealloc, /* tp_dealloc */
0, /* tp_print */
0, /* tp_getattr */
0, /* tp_setattr */
0, /* tp_compare */
(reprfunc)type_repr, /* tp_repr */
0, /* tp_as_number */
0, /* tp_as_sequence */
0, /* tp_as_mapping */
(hashfunc)_Py_HashPointer, /* tp_hash */
(ternaryfunc)type_call, /* tp_call */
0, /* tp_str */
(getattrofunc)type_getattro, /* tp_getattro */
(setattrofunc)type_setattro, /* tp_setattro */
0, /* tp_as_buffer */
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC |
Py_TPFLAGS_BASETYPE | Py_TPFLAGS_TYPE_SUBCLASS, /* tp_flags */
type_doc, /* tp_doc */
(traverseproc)type_traverse, /* tp_traverse */
(inquiry)type_clear, /* tp_clear */
type_richcompare, /* tp_richcompare */
offsetof(PyTypeObject, tp_weaklist), /* tp_weaklistoffset */
0, /* tp_iter */
0, /* tp_iternext */
type_methods, /* tp_methods */
type_members, /* tp_members */
type_getsets, /* tp_getset */
0, /* tp_base */
0, /* tp_dict */
0, /* tp_descr_get */
0, /* tp_descr_set */
offsetof(PyTypeObject, tp_dict), /* tp_dictoffset */
type_init, /* tp_init */
0, /* tp_alloc */
type_new, /* tp_new */
PyObject_GC_Del, /* tp_free */
(inquiry)type_is_gc, /* tp_is_gc */
};
这里可以看到它的类型对象本身引用了自己。。。。。
以后可以看到,所有的python类型对象都将它自己的类型对象指向了PyType_Type
好了。。基本上比较粗略的了解了python的对象结构。。。。。