同样的,我们首先让列表 l1 和 l2 同时指向了[1, 2, 3]这个对象 。

文章插图
由于列表是可变的,所以 l1.append(4) 不会创建新的列表,只是在原列表的末尾插入了元素 4,变成[1, 2, 3, 4] 。由于 l1 和 l2 同时指向这个列表,所以列表的变化会同时反映在 l1 和 l2 这两个变量上,那么,l1 和 l2 的值就同时变为了[1, 2, 3, 4] 。

文章插图
另外,需要注意的是,Python 里的变量可以被删除,但是对象无法被删除 。比如下面的代码:
arr = [1, 2, 3]del arrdel arr 删除了 arr 这个变量,从此以后你无法访问 arr,但是对象[1, 2, 3]仍然存在 。Python 程序运行时,其自带的垃圾回收系统会跟踪每个对象的引用 。如果[1, 2, 3]除了 arr 外,还在其他地方被引用,那就不会被回收,反之则会被回收 。由此可见,在 Python 中:
1、变量的赋值,只是表示让变量指向了某个对象,并不表示拷贝对象给变量;而一个对象,可以被多个变量所指向 。
2、可变对象(列表,字典,集合等等)的改变,会影响所有指向该对象的变量 。
3、对于不可变对象(字符串、整型、元组等等),所有指向该对象的变量的值总是一样的,也不会改变 。但是通过某些操作(+= 等等)更新不可变对象的值时,会返回一个新的对象 。
4、变量可以被删除,但是对象无法被删除 。
Python 函数的参数传递从上述 Python 变量的命名与赋值的原理讲解中,相信你能举一反三,大概猜出 Python 函数中参数是如何传递了吧?
这里首先引用 Python 官方文档中的一段说明:
“Remember that arguments are passed by assignment in Python. Since assignment just creates references to objects, there’s no alias between an argument name in the caller and callee, and so no call-by-reference per Se.”
准确地说,Python 的参数传递是赋值传递 (pass by assignment),或者叫作对象的引用传递(pass by object reference) 。Python 里所有的数据类型都是对象,所以参数传递时,只是让新变量与原变量指向相同的对象而已,并不存在值传递或是引用传递一说 。比如,我们来看下面这个例子:
def my_func1(b):b = 2a = 1my_func1(a)a1这里的参数传递,使变量 a 和 b 同时指向了 1 这个对象 。但当我们执行到 b = 2 时,系统会重新创建一个值为 2 的新对象,并让 b 指向它;而 a 仍然指向 1 这个对象 。所以,a 的值不变,仍然为 1 。那么对于上述例子的情况,是不是就没有办法改变 a 的值了呢?答案当然是否定的,我们只需稍作改变,让函数返回新变量,赋给 a 。这样,a 就指向了一个新的值为 2 的对象,a 的值也因此变为 2 。
def my_func2(b):b = 2return ba = 1a = my_func2(a)a2不过,当可变对象当作参数传入函数里的时候,改变可变对象的值,就会影响所有指向它的变量 。比如下面的例子:def my_func3(l2):l2.append(4)l1 = [1, 2, 3]my_func3(l1)l1[1, 2, 3, 4]这里 l1 和 l2 先是同时指向值为[1, 2, 3]的列表 。不过,由于列表可变,执行 append() 函数,对其末尾加入新元素 4 时,变量 l1 和 l2 的值也都随之改变了 。但是,下面这个例子,看似都是给列表增加了一个新元素,却得到了明显不同的结果 。def my_func4(l2):l2 = l2 + [4]l1 = [1, 2, 3]my_func4(l1)l1[1, 2, 3]为什么 l1 仍然是[1, 2, 3],而不是[1, 2, 3, 4]呢?要注意,这里 l2 = l2 + [4],表示创建了一个“末尾加入元素 4“的新列表,并让 l2 指向这个新的对象 。这个过程与 l1 无关,因此 l1 的值不变 。当然,同样的,如果要改变 l1 的值,我们就得让上述函数返回一个新列表,再赋予 l1 即可:
def my_func5(l2):l2 = l2 + [4]return l2l1 = [1, 2, 3]l1 = my_func5(l1)l1[1, 2, 3, 4]这里你尤其要记住的是,改变变量和重新赋值的区别:1、my_func3() 中单纯地改变了对象的值,因此函数返回后,所有指向该对象的变量都会被改变;
2、但 my_func4() 中则创建了新的对象,并赋值给一个本地变量,因此原变量仍然不变 。
至于 my_func3() 和 my_func5() 的用法,两者虽然写法不同,但实现的功能一致 。不过,在实际工作应用中,我们往往倾向于类似 my_func5() 的写法,添加返回语句 。这样更简洁明了,不易出错 。
总结今天,我们一起学习了 Python 的变量及其赋值的基本原理,并且解释了 Python 中参数是如何传递的 。和其他语言不同的是,Python 中参数的传递既不是值传递,也不是引用传递,而是赋值传递,或者是叫对象的引用传递 。
推荐阅读
- Python爬虫遇到验证码的几种处理方式,文章末尾有源码
- python:栈的理解与应用
- 班章五寨都在那里,今大福班章金沱
- 玻璃膜是贴在玻璃外面还是里面 玻璃单向膜在外面真的看不见吗
- 枸杞鸽子煲靓汤的做法
- 斗罗大陆圣魂村武魂觉醒 斗罗大陆武魂在哪里觉醒
- 北京的茶道介绍,奥运村里的中国式智慧
- 高铁|时速350公里!郑渝高铁即将全线开通:郑州至重庆4小时可达
- 空调如何清洗过滤网 柜机空调清洗怎么清洗过滤网
- Python的从入门到精通的完整学习路线图
