函数的参数到底是传递的一份复制的值,还是对内存的引用?
我们看下面一段代码:
- a = []
- def fun(x):
- x.append(1)
- fun(a)
- print(a)
想想一下:如果传递的是一份复制的值,那么列表 a 应该是不会变化的,还是空列表;如果传递的是引用,那么 a 应该是 [1]。
执行一下看到输出结果是 [1],即证明函数参数传递的是引用。
但是,再看下面的代码:
- a = 1
- def fun(x):
- x = 2
- return x
- ret = fun(a)
- print(a)
- print(ret)
如果按照上面的理解,函数参数传递的是引用,那么 a 的值应该变为 2,但是输出却是 1,这是为什么?
解释:
python 中所有的变量都可以理解是内存中一个对象的 "引用"。这里需要记住的是类型是属于对象的,而不是变量。而对象有两种,"可更改"(mutable)与 "不可更改"(immutable)对象。在 python 中,strings, tuples, 和 numbers 是不可更改的对象,而 list,dict 等则是可以修改的对象。(这就是这个问题的重点)
当一个引用传递给函数的时候, 函数自动复制一份引用, 这个函数里的引用和外边的引用没有半毛关系了。所以第二个例子里函数把引用指向了一个不可变对象, 当函数返回的时候, 外面的引用是不会改变的。而第一个例子就不一样了, 函数内的引用指向的是可变对象, 对它的操作就和定位了指针地址一样, 在内存里进行修改。
不过,有的时候我们确实需要在函数内部修改全局的不可修改的对象,这个时候怎么办呢?
- a = 1
- def fun(x):
- global a
- x = 2
- a = 'hello'
- return x
- ret = fun(a)
- print(a)
- print(ret)
输出:
hello
2
我们看到通过关键字 global,我们将 a 的值做了修改。但是我们建议尽量减少这种方式的使用,因为我们在函数内部修改了全局变量的值,如果后面还有其他函数使用这个变量的时候可能还认为 a 的值是 1,因此导致出错,而且不易排查。
另:全局变量约定使用大写字母。
来源: http://www.bubuko.com/infodetail-2004334.html