python的赋值

来源:互联网 发布:加载数据翻译 编辑:程序博客网 时间:2024/05/16 23:53
赋值是语言里最基本的语句,我到现在才发现我之前对python里的赋值的理解一直都是错的。

python里的赋值使用的是原对像的引用,而不是拷贝。因此,在进行b=a这样的赋值之后,对b进行操作,是有可能会影响a的值的。例如:
>>> a = [1,2,3]
>>> b = a
>>> b.append(4)
>>> print(a,b)
[1, 2, 3, 4] [1, 2, 3, 4]

使用 += 也有一样的效果:
>>> a = [1,2,3]
>>> b = a
>>> b += [4]
>>> print(a,b)
[1, 2, 3, 4] [1, 2, 3, 4]

但是,对b进行重新赋值,则不影响a
>>> a = [1,2,3]
>>> b = a
>>> b = a + [4]
>>> print (a,b)
[1, 2, 3] [1, 2, 3, 4]
因为a+[4]是通过拷贝生成了新的对像,然后把b重新绑定到新的对像上,此后b和a就没有关系了。
由这个例子可以看出:b += a 并不总是等价于 b = b + a 的

函数的参数传递跟赋值的道理相同。在C语言书上讲函数的参数传递时有个的例子,是在函数体中交换两个变量的值,并不影响函数体外的变量。这很容易让人觉得函数体内是与世隔绝的,形参随便改用都不会对外面有影响。但这套用到python上就不对了,虽然python跟C语言中传值的写法相同,没有使用明显的指针或取地址运行符,但确实是使用了引用的方式进行传递。因此,python函数体内对形参进行的操作也有可能对外面有副作用,需要留意。
>>> def fun(a):
a += a
print(a)

>>> x = [1,2,3]
>>> fun(x)
[1, 2, 3, 1, 2, 3]
>>> print(x)
[1, 2, 3, 1, 2, 3]

不过,当使用数字、元组、字符串等不可变的对像时,情况又不一样了。同样是上面那个fun函数,以字符串为参数时:
>>> s = 'abc'
>>> fun(s)
abcabc
>>> print(s)
abc
字符串s在fun运行完后并没有被改变,因为字符串是不可变的对像,字符串的+=操作与数组的+=操作不一样,前者进行了拷贝,后者没有。

python中数组的构建同样涉及到引用的问题。我们构建一维数组可以简单的使用乘号*来完成
>>> A = [0]*5
>>> print(A)
[0, 0, 0, 0, 0]
>>> A[1] = 1
>>> print(A)
[0, 1, 0, 0, 0]

但是,在第二维就不可以这么做了
>>> A = [0]*5
>>> B = [A]*3
>>> print(B)
[[0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0]]
>>> B[1][1]=1
>>> print(B)
[[0, 1, 0, 0, 0], [0, 1, 0, 0, 0], [0, 1, 0, 0, 0]]
>>> print(A)
[0, 1, 0, 0, 0]

因为B=[A]*3就是B=[A,A,A],B里的三个元素是指向同一个对像的,B[1][1]=1就会同时修改三行中的值,这样构建出来的数组一般是不适用的。此时构建多维数组就必需要使用拷贝的方法进行。
对数组进行拷贝有多种方法,
>>> A = [1,2,3,4,5]
>>> B = A[:]
>>> C = [x for x in A]
>>> D = list(A)
B、C、D都是A的拷贝,对其进行修改不会对A有影响。
数组的第二维要用for进行,如:
>>> E = [A[:] for i in range(3)]
>>> F = [[x for x in A] for i in range(3)]
>>> G = [list(A) for i in range(3)]

对于一般对像的拷贝,可以用copy模块。
>>> import copy
>>> A = [1,2,3]
>>> B = copy.copy(A)
copy.copy()可以生成对像的浅拷贝,前面使用的数据拷贝方法都是浅拷贝。如果要对对像的内容和属性进行分别的和递归的拷贝,可以使用copy.deepcopy()
原创粉丝点击