Python 中的對象概述
(你也可以在我的博客閱讀這篇文章)
在 Python 的世界中,一切皆對象。 int / list / dict / ... 都是對象,除此之外,函數、類本身也是對象,那麼,這些對象究竟是什麼呢?
從結果看,Python 中的對象是 C 語言中結構體在堆上申請的一片內存區域。而在具體實現上,這裡先簡單描述一下。
萬物基於 MIUI: PyObject
在 Python 中,所有對象都共有一些特性,這些特性定義在 PyObject 中。PyObject 定義在Include/object.h 中:
#define PyObject_HEAD n _PyObject_HEAD_EXTRA n Py_ssize_t ob_refcnt; n struct _typeobject *ob_type;nntypedef struct _object {n PyObject_HEADn} PyObject;n
簡化後即為:
typedef struct _object {n int ob_refcnt; n struct _typeobject *ob_type;n} PyObject;n
在 PyObject 中,ob_refcnt 用以記錄對象的引用數(與引用計數的內存回收相關,這裡暫且不表),當有新的指針指向某對象時,ob_refcnt 的值加 1, 當指向某對象的指針刪除時,ob_refcnt 的值減 1,當其值為零的時候,則可以將該對象從堆中刪除(事實上並不會立即刪除,這裡暫且不表)。除了 ob_refcnt 之外,還有一個 指向 _typeobject 指針 ob_type。這個結構體用於表示對象類型。跳過 _typeobject,可以發現, Python 對象的核心在於一個引用計數和一個類型信息。
PyObject 定義的內容會出現在每個對象所佔內存的開始部分。
定長對象與變長對象
在 Python 中,除了 bool float 這樣的定長對象(一旦確定下來需要的內存,便不再有改動),還有另外一種對象:長度可變的對象。這種對象在 Python 的實現中通過 PyVarObject 結構體來表示:
#define PyObject_VAR_HEAD n PyObject_HEAD n Py_ssize_t ob_size; /* Number of items in variable part */nntypedef struct {n PyObject_VAR_HEADn} PyVarObject;n
事實上,就是在 PyObject 的基礎上,多了一個 ob_size 變數,用以標識對象的長度(是長度,不是內存佔用)。也就是說,其實 PyVarObject 就是 PyObject 的一個拓展,於是,在 Python 中,所有的對象都可以通過 PyObject * 指針來引用,這一點非常重要,它使得很多操作變得統一(這篇博客暫不詳述)。
由此,Python 中所有對象在實現的時候,內存無非如下兩種情況:
定長對象 變長對象n+-----------+ +-----------+n| ob_refcnt | | ob_refcnt |n+-----------+ +-----------+n| ob_type | | ob_type |n+-----------+ +-----------+n| | | ob_size |n| | +-----------+n| other | | |n| | | other |n| | | |n+-----------+ +-----------+n
道生一:PyTypeObject
在描述 PyObject 的時候,提到了一個 _typeobject 結構體。那麼,它是幹什麼的呢?想像一下,一個對象在創建的時候需要多少內存、這個對象的類名是什麼等等信息,又是如何記錄和區分的呢?
_typeobject(也就是PyTypeObject)可以被稱之為「指定對象類型的類型對象」,其定義如下:
typedef struct _typeobject {n PyObject_VAR_HEADn const char *tp_name; /* For printing, in format "<module>.<name>" */n Py_ssize_t tp_basicsize, tp_itemsize; /* For allocation */nn // ...... 省略部分暫時不關心的內容nn} PyTypeObject;n
可以理解為,PyTypeObject 對象是 Python 中面向對象理念中「類」這個概念的實現,這裡只是簡單介紹其定義中的部分內容:
- ty_name:類型名
- tp_basicsize, tp_itemsize:創建類型對象時分配的內存大小信息
- 被省略掉的部分:與該類型關聯的操作(函數指針)
這裡只是簡單描述,上面的內容有些偏頗,暫不必過分深究。
再看一眼 PyTypeObject 的定義,可以發現在最開始也有一個 PyObject_VAR_HEAD,這意味著它也是一個對象。那麼,PyTypeObject 既然是指示類型的對象,那麼它的類型又是什麼呢?答案是 PyType_Type:
PyTypeObject PyType_Type = {n PyVarObject_HEAD_INIT(&PyType_Type, 0)n "type", /* tp_name */n sizeof(PyHeapTypeObject), /* tp_basicsize */n sizeof(PyMemberDef), /* tp_itemsize */n (destructor)type_dealloc, /* tp_dealloc */n // ...... 省略了部分內容n};n
事實上,它就是 Python 語言中的 type 對象就是 PyType_Type,它是所有 class 的 class,在 Python 中叫做 metaclass。其實,在實現中它的 ob_type 指針又指向了自己本身,既是:
PyType_Typen+-----------+<-------+n| ob_refcnt | |n+-----------+ |n| ob_type +--------+n+-----------+n| |n| other |n| |n+-----------+n
小結
簡單概述了 Python 中的對象的最模糊的概念。
推薦閱讀:
※【源碼眾讀】進度報告,這不是一個假活動
※Android Framework源碼當中哪些類有必要進行深入學習?
※國外有哪些優秀的源碼剖析類書籍?
