对象
在计算机上,一个对象实际上就是一片被分配的内存空间,这些内存可能是连续的,也有可能是离散的,这都不重要,重要的是这片内存在更高的层次上可以作为一个整体来考虑,这个整体就是一个对象。
实际上,PyObject是Python中不包含可变长度数据的对象的基石,而对于包含可变长度数据的对象,它的基石是PyVarObject。这两个结构体构成了python对象机制的核心基石,他们分别由PyObject_HEAD和PyObject_VAR_HEAD来进行操作。
在python中类型也是对象,所以type()返回的时对象不是简单的字符串。
#define PyObject_HEAD
_PyObject_HEAD_EXTRA
int ob_refcnt;
struct _typeobject *ob_type;
#define PyObject_VAR_HEAD
PyObject_HEAD
int ob_size;
在PyObject_HEAD的定义中,有一个ob_refcnt的整形变量,这个变量的作用是实现引用计数机制。对于某一个对象A,当有一个新的PyObject *引用该对象时,A的引用计数应该增加;而当这个PyObject *被删除时,A的引用计数应该减少。当A的引用计数减少到0时,A就可以从堆上被删除,以释放出内存供别的对象使用。
在PyObject_HEAD中,我们注意到ob_type是一个指向_typeobject结构体的指针,那么这个结构体是一个什么东西呢?实际上这个结构体也是一个对象,它是用来指定一个对象类型的类型对象。在Python中实际上对象机制的核心非常的简单,一个是引用计数,一个就是类型。
而对于拥有可变长度数据的对象,这样的对象通常都是容器,我们可以在PyObject_VAR_HEAD中看到ob_size这个变量,这个变量实际上就是指明了该对象中一共包含了多少个元素。注意,ob_size指明的是元素的个数,而不是字节的数目。比如对于Python中最常用的list,它就是一个PyVarObject对象,如果某一时刻,这个list中有5个元素,那么PyVarObject.ob_size的值就是5。
在PyObject_HEAD中,我们注意到ob_type是一个指向_typeobject结构体的指针,那么这个结构体是一个什么东西呢?实际上这个结构体也是一个对象,它是用来指定一个对象类型的类型对象。在Python中实际上对象机制的核心非常的简单,一个是引用计数,一个就是类型。
而对于拥有可变长度数据的对象,这样的对象通常都是容器,我们可以在PyObject_VAR_HEAD中看到ob_size这个变量,这个变量实际上就是指明了该对象中一共包含了多少个元素。注意,ob_size指明的是元素的个数,而不是字节的数目。比如对于Python中最常用的list,它就是一个PyVarObject对象,如果某一时刻,这个list中有5个元素,那么PyVarObject.ob_size的值就是5。
None,Python有一个特殊的None对象,它仅有一个值,None。None值等同于C语言的null。None没有属性,总等于布尔值的false。
字符串对象
在对PyIntObject的分析中,我们看到了Python中的具有不可变长度数据的对象(定长对象)。在Python中,还大量存在着另一种对象,即具有可变长度数据的对象(变长对象)。与定长对象不同,对于变长对象而言,对象维护的数据的长度在对象定义时是不知道的。对于PyIntObject来说,其维护的数据的长度在对象定义时就已经确定了,是一个long变量的长度;而可变对象维护的数据的长度只能在对象创建时才能确定,考虑一下,我们只能在创建一个字符串或一个列表时才知道它们所维护的数据的长度,在此之前,对这个信息,我们一无所知。
在变长对象中,实际上还可分为可变对象(mutable)和不可变对象(immutable),可变对象是在对象创建之后,其维护的数据的长度还能变化的对象,比如一个list被创建后,可以向其中添加元素或删除元素,这些操作都会改变其维护的数据的长度;而不可变对象所维护的数据在对象创建之后就不能再改变了,比如Python中的string和tuple,它们都不支持添加或删除的操作。
在Python中,PyStringObject是对字符串对象的抽象和表示。PyStringObject是一个拥有可变长度内存的对象,这一点非常容易理解,因为对于表示”Hi”和”Python”的两个不同的PyStringObject对象,其内部需要的保存字符串内容的内存空间显然是不一样的。但同时,PyStringObject对象又是一个不变对象(Immutable)。当创建了一个PyStringObject对象之后,该对象内部维护的字符串就不能再被改变了。这一点特性使得PyStringObject对象能作为PyDictObject的键值,但同时也使得一些字符串操作的效率大大降低,比如多个字符串的连接操作。