现在的位置: 首页 > 操作系统 > 正文

Python中mutable与immutable和二维列表的初始化问题

2020年02月06日 操作系统 ⁄ 共 1284字 ⁄ 字号 评论关闭

初始化一个shape为(3,3)的二维列表,正确的写法是这样的:

a = [[None] * 3 for i in range(3)]print(a)

a[0][0] = 1print(a)

#经过测试没有问题# 输出:#[[None, None, None], [None, None, None], [None, None, None]]#[[1, None, None], [None, None, None], [None, None, None]]

但是,如果写成这样:

a = [[None] * 3] * 3print(a)

# 输出 : [[None, None, None], [None, None, None], [None, None, None]]

看起来像是没有问题,实际上,如果进行赋值操作,就会发现问题:

a[0][0] = 1print(a)

# 输出:[[1, None, None], [1, None, None], [1, None, None]]

结果三行的对应位置的元素全都改变了!(就因为这个问题找了好长时间的bug… =_=|||)后来知道,这个问题与Python中数据类型的分类有关,所以在这里记录一下,存个档。

步入正题,在Python中有一句话:万物皆对象(好像OOP都是这么说。。),在Python中所写的一切都可以看作是一个对象,比如定义的整数、浮点数以及列表,元组等,但是这些对象也有区别,这些对象,有些属于mutable(可变),有些则是属于immutable(不可变),这是什么意思呢?先看一个例子:# 这里定义一个整数 id()函数可以查看对象的内存位置

a = 3print(id(a))a += 1print(id(a))

#输出:# 94034634295264# 94034634295296

# 接下来定义一个列表:a = [1,2,3]print(id(a))a[0] = 100print(id(a))

# 输出:# 139637076845448# 139637076845448

通过对比,不难发现,对数值,比如整数、浮点数进行改变,内存的位置会发生改变,但是对列表,字典之类的进行改变,则不会改变内存位置。

实际上,对于整数、浮点数,改变值的时候,实际上是新开辟了一块内存,然后把加法的结果填充到这快内存中,然后再把a指向这块新的内存。

这里提到了“指向”,如果学过C或者C++,可能会想到指针或者引用,再Python中也有说引用的,那么这里就可以看出两种语言的“引用”是不同的了,C++中,对引用的数据进行改变,这个位置应该是不变的,而再Python中,显然,就像上面,相当于改变了“引用”,而不是内存的数据。

这里可能有点绕,不过这里也就是所说的mutable和immutable的问题了,在Python中,immutable的类型有整数、浮点数、字符串以及元组等等,而mutable的类型有list,dict以及自定义的类型。

那么回到上面一开始的问题中,知道了list是mutable的,所以在创建的时候,并不是赋值到了新的位置,只是创建了三个指针(a[0], a[1], a[2])指向了同一块内存而已,所以,改变其中一个的某个元素,会对所有的元素产生影响。

抱歉!评论已关闭.