Python 可变类型与不可变类型
目录

之前一直没太注意,只知道string类型是不可变类型,现在研究到闭包,原来Python中很多类型都是不可变类型:

  • 不可变(mutable)类型:int, long, float, string, tuple, frozenset
  • 可变类型(immutable)类型:list, dict

Python中所有变量都是值的引用,也就说变量通过绑定的方式指向其值。 而这里说的不可变指的是值的不可变。 对于不可变类型的变量,如果要更改变量,则会创建一个新值,把变量绑定到新值上,而旧值如果没有被引用就等待垃圾回收。

不可变的类型还有一个特性,就是可以计算其hash值,这样才能进一步作为字典的key。

对于可变类型,其作为函数参数的默认值或者类的成员要尤其小心,比如作为函数参数:

def f(a = []):
a.append(1)
return a
print f()
print f()
print f()
[1]
[1, 1]
[1, 1, 1]

按照不可变类型的习惯,这里应该输出三个[1]。 但是a的值却是继承了之前的值,着有点像c语言的静态变量。 这是因为变量f就是一个函数类型的实例,其默认参数存储在f.__defaults__中,作为可变类型的a其指向一个序列。 还函数定义时创建了f对象,并对其成员a赋予默认的[]。 如果有参数,就会把a绑定到那个参数上。如果没有,则使用默认的a。 这个例子使用了默认的a值,每次调用时改变了序列的内容。 这里也进一步理解函数作为第一类型的特点。

类也具有相似的问题:

class b:
x = []
y = 0
def set(self):
self.x.append(1)
self.y += 1
def get(self):
return self.x, self.y

a1 = b()
a1.set()
print a1.get()

a2 = b()
a2.set()
print a2.get()
([1], 1)
([1, 1], 1)

xy都是class b的属性并给出了默认值。 这里猜测a1a2两个实例在构造的时候,拷贝了class b的属性,因此a1a2的属性都指向共同的值。 这样的属性,叫类属性。

在Java中,静态变量 (在 Python 中叫类属性) 和实例变量 (在 Python 中叫数据属性) 两者都是紧跟在类定义之后定义的 (一个有 static 关键字,一个没有)。在 Python 中,只有类属性可以定义在这里,数据属性定义在 init 方法中,如下:

class b:
def __init__(self):
self.x = []
self.y = 0
def set(self):
self.x.append(1)
self.y += 1
def get(self):
return self.x, self.y

类属性可以作为类级别的常量来使用,但是它们不是真正的常量。你也可以修改它们。 看来要找本深入Python的书看看了,不能只是需求驱动。

发表评论