动态类型

变量,对象和引用

变量在赋值的时候创建,它可以引用任何类型的对象,并且必须在引用之前赋值。

a = 3

所有赋值操作有三个步骤:

  1. 创建一个对象来代表值3
  2. 创建一个变量a,如果它还没有创建
  3. 将变量与新的对象3相连接

在运行a=3后,变量a变成对象3的一个引用,在内部,变量实际上是到对象内存空间的一个指针。

类型属于对象,而不是变量

a = 3
a = 'spam'
a = 1.23

变量名没有类型,我们只是把a修改为不同的对象的引用。因此,没有改变a的类型,而是让变量引用了不同类型的对象。

每个对象都包含了一个头部信息,其中标记了这个对象的类型。

对象的垃圾回收

每当一个变量名被赋予了一个新的对象,之前那个对象占用的空间就会被回收。这种技术叫做垃圾回收。

x = 42
x = 'shrubbery'
x = 3.1415
x = [1, 2, 3]

在内部,python在对象中保持了一个计数器,计数器记录了当前指向该对象的引用的数目。一旦这个计数器被设置为零,这个对象的内存空间就会自动回收。

共享引用

a = 3
b = a

a和b引用了相同的对象,指向了相同的内存空间。多个变量引用同一个对象,这叫共享引用。

a = 3
b = a
a = 'spam'

这时候,b仍然引用原来的对象3。

a = 3
b = a
a = a + 2

a会赋值为一个完全不同的对象,而不会影响到b。b还是3对象。

共享引用和在原处修改

对于支持在远处修改的对象,共享引用时需要小心,因为对一个变量名的修改会影响其他变量。

L1 = [2, 3, 4]
L2 = L1
L1[0] = 24

L1
#[24, 3, 4]
L2
#[24, 3, 4]

列表对象内的元素的远处修改会印象程序其他部分。如果不想要这样的现象发生,需要python拷贝对象,而不是创建引用。拷贝列表可以用内置列表函数,或者标准库copy模块,或者从头到尾的分片。

L1 = [2, 3, 4]
L2 = L1[:]
L1[0] = 24

L1
#[24, 3, 4]
L2
#[2, 3, 4]

共享引用和相等

x = 42
x = 'shrubbery'

因为python会缓存并且复用小的整数和小的字符串,这里的对象42也许并不会回收,它可能会保存在一个系统表中,等待下一次代码生成一个42来重复利用。

python中有两种办法检查是否相等。看共享引用的例子:

L = [1, 2, 3]
M = L

L == M
#True

L is M
#True

==操作符检查值是否相等,is操作符,检查对象的同一性,如果两个变量指向同一个对象,那么会返回True。

实际上,is比较实现引用的指针,所以这是一种检查共享引用的方法。如果变量名的引用值相等,但是是不同的对象,它的返回值会是False。

L = [1, 2, 3]
M = [1, 2, 3]

L == M
#True

L is M
#False

但当我们对小的数字做同样的操作:

x = 42
y = 42

x == y
#True

x is y
#True

因为小的数字和字符串被缓存复用了,所以is告诉我们它们引用的使用一个对象。

你可以向python查询一个对象引用的次数:在sys模块中的getrefcount函数会返回对象的引用次数。例如,在IDLE GUI中查询整数对象1时,会返回有837次引用。

import sys
sys.getrefcount(1)
#837

 

posted @ 2017-08-08 23:41  hahazexia  阅读(177)  评论(0编辑  收藏  举报