python不可变数据类型及函数参数传递浅析

这几天我在用Python写一个简单的用户密码暴力破解程序,以前没有真的拿python写过实用程序,都是些几行的小工具。用过之后才发现一些以前没有注意到的小细节。

Python的数据类型很有趣,可以分为两大类一类叫做可变(mutable)数据类型,一类叫做不可变(immutable)数据类型。

Python中的变量相当于一个void*指针它可以指向任意数据类型,所谓可变数据类型也就是变量所指的内存区域是可改写,而不可变数据类型顾名思义即变量所指的内存区域不可改写的,内存区的数据是1就是1,不能改写为2。

这不是最好玩的,最好玩的在这里:

python的不可变类型:string,integer,tuple

可变数据类型为:list,dict

没错integer也是不可变的数据类型哦,你可能会奇怪

Python Code:
>>>a = 15
>>>a += 5
>>>print a

显示20

这a的内容不是变了吗?其实当python解释器发现要改写不可变数据类型的时候他会创建一个新的内存块,在其中填入更新后的内容,再把变量指向新的内存块,上面那段代码用c语言来模拟就是

C Code:
void * a;
void * mb1;
void * mb2;
a = mb1 = malloc(sizeof(int));
*(int*)a = 15;   /* python: a = 15 */
a = mb2 = malloc(sizeof(int));
*(int*)a = 15 + 5; /* python: a += 5 */
printf("%d\n", *(int*)a);

首先a = 15,python给a分配了一个内存块mb1并存入INT型值15
之后a += 5, python发现对int不可变类型进行改写,python抛弃了原有的内存块(mb1,保存15的那个),并创建一个新的内存块mb2,并保存值为15+5=20,这样a的值就变为20,而没有改写任何内存块。之后python的垃圾回收器发现原来的内存块没有被引用于是自动释放mb1: free(mb1)

这个在函数传递中就更有意思了,虽然python传递的参数形式本质上是引用传递,但是会产生值传递的效果

Python Code:
def swap(a, b):
    tmp, a, b = a, b, a
c, d = 15, 20
swap(c, d)
print c,d

实际上c,d是将它们的引用传递给a,b。如下图

但是运行的结果 15 20

证明c,d的值并没被改变。函数调用时,a,b分别指向c,d的引用:内存块mb1,和内存块mb2。 当改写a,b的值时,python会为a,b分配新的空间,a,b分别指向新的空间mb3, mb4,而tmp=a所以tmp则指向原先函数实参C的引用MB1,函数运行后如下图

因此c,d的值当然没被改变。

总结一下,当python所传递的参数是不可变类型时,实际上函数有值传递的效果(形参的值被修改不会影响实参)

如果你要形参的修改影响实参请用可变数据类型,上面的代码修改如下:

Python Code:
def swap(a, b):
	tmp, a[0], b[0] = a[0], b[0], a[0]

c, d = [15], [20]
swap(c, d)
print c[0],d[0]

运行结果20 15

发表评论

电子邮件地址不会被公开。 必填项已用*标注

This site uses Akismet to reduce spam. Learn how your comment data is processed.