分类: Python/Ruby
2011-07-24 19:42:08
在学习更复杂的对象类型之前,先掌握python的动态类型这一概念,是十分必要的。动态类型以及它提供的多态性是python语言简洁性和灵活性的基础。
----------------------------------------------------------------------------------------------
变量与类型
变量是系统表的元素,并拥有指向对象连接的空间(Variables are entries in system table,
with spaces for links to objects)。变量绝不会有任何的类型或与类型相关的信息。变量是通用的,它只是在某个时间,某个位置简单的引用了一个对象而已。类型属于对象。
变量、声明与初始化
因为它没有类型,所以变量不需要声明;因为它会在程序运行过程中自动创建,并由此获得多态性,所以不应该被声明。但是需要被初始化,并且要在使用前赋值。例如,变量初始化,会将对象的引用计数器初始化为0.
对象与类型
Ⅰ对象在python的作用,与数据结构在C/C++中的作用一样。而变量名在python中的作用,与指针在C/C++中类似。
Ⅱ对象被分配到足够的内存空间以表示它的值,它与这块内存空间紧密相关。
Ⅲ 对象有复杂的结构。python的对象体系用C实现,对象结构对应C中的结构体。
typedef struct _typeobject
{
PyObject_VAR_HEAD /*与C实现有关的宏*/
char *tp_name; /*in format "
int tp_basicsize, tp_itemsize; /* For allocation */
/* Methods to implement standard operations */
destructor tp_dealloc;
printfunc tp_print;
……
/* More standard operations (here for binary compatibility) */
hashfunc tp_hash;
ternaryfunc tp_call; ……
} PyTypeObject;
可以说,对象就是一块有着一定结构和一些方法的内存空间。
Ⅳ 对象有两个标准的头部信息。一个是类型标识符,一个是引用计数器。引用计数器与python的垃圾回收有关。
变量与对象
从变量到对象的连接称为引用,它在底层通过指针实现。使用变量,即是通过变量名引用对象。
从对象到引用的过程:
>>> a = 3
1.创建一个对象,它的值是3
2.如果a未被创建,则创建一个名为a的变量
3.将a与对象3像连接
---------------------------------------------------------------------------------------------
对象的垃圾收集与缓存复用机制
每当变量名被赋予一个新的对象,它先前能引用的对象就会被销毁(如果那个对象没有被其他变量引用)。
这就是垃圾回收机制。它的实现过程与对象的引用计数器有关:当变量初始化时,计数器同时初始化为0,
随着对象会被变量引用,计数器值会增加;当引用结束,计数器值减少;当计数器又回到0时,对象同时
被回收。
作为垃圾回收机制的补充,python有一个循环检测器在及时地检测并回收带有循环引用的对象。这个功能
是可选的。
注意,有的时候垃圾回收机制会影响程序的性能。所以,可以在某处事先手动关闭垃圾回收功能,在那个
更需要性能的程序模块之后开启回收。
并不是所有的对象在引用它的变量指向别处后离开被销毁,如小的整数和小的字符串,它们依然会短时间存在于系统表中,并可以被引用。
情况一:
>>> l = [1, 2, 3]
>>> m = [1, 2, 3]
>>> l == m
True
>>> l is m #m = [1, 2, 3]创建了新对象
False
情况二:
>>> x = 2
>>> y = 2
>>> x == y
True
>>> x is y #y=2,并没有创建一个新对象
True
----------------------------------------------------------------------------------------------
共享引用
在某一时刻,一个变量只能引用一个对象,但是一个对象可以被多个变量引用,这就是共享引用:
>>> a = 3
>>> b = a
>>> b
3
在运行b=a时,b并没有再次创建一个值为3的对象,而只是与先前那个对象建立了连接。并且,这种连接
与a没有多大关联,若a再被赋予新值,它将指向一个新建的对象,所以:
>>> a = 'spam'
>>> b
3
但是情况并非总是这样。当a与b共享引用时,在a所引用的对象发生变化,可能只是在原有对象的基础上进行的修改,于是,b所引用的对象的值也发生了修改:
>>> a = [1, 2, 3]
>>> b = a
>>> a[0] = 5
>>> a
[5, 2, 3]
>>> b
[5, 2, 3]
这种情况也许不是你想要的。为了不让这样的事情发生,在不同的情况下有不同的方法解决这个问题。如:
>>> a = [1, 2, 3]
>>> b = a[:]
>>> a[0] = 4
>>> a
[4, 2, 3]
>>> b
[1, 2, 3]
上面使用的方法是分片拷贝技术,更通用的做法是:
>>> import copy
>>> a = [1, 2, 3]
>>> b = copy.copy(a) #b = copy.deepcopy(a)
>>> a[0] = 4
>>> a
[4, 2, 3]
>>> b
[1, 2, 3]
----------------------------------------------------------------------------------------------
如果两个变量引用的对象的值相等,有的时候它们的确引用了同一个对象,有的时候却是引用了两个值一样
对象,情况一(共享引用):
>>> l = [1, 2, 3]
>>> m = l
>>> l == m
True
>>> l is m
True
情况二:
>>> l = [1, 2, 3]
>>> m = [1, 2, 3]
>>> l == m
True
>>> l is m
False
还可以用下面方法:
>>> import sys
>>> x = 32
>>> sys.getrefcount(32) #测试32被引用的次数
16
>>> y = 32
>>> sys.getrefcount(32) #再次测试发现32引用次数增加1,这个32不是新建对象
17