8.对变量的再认识
1.1. 变量引用
人们经常使用“变量是盒子”这样的比喻,但是这有碍于理解面向对象语言中的引用式变量。Python 变量类似于 Java 中的引用式变量,因此最好把它们理解为附加在对象上的标注或便签。
在示例中所示的交互式控制台中,无法使用“变量是盒子”做解释。示意图说明了在 Python 中为什么不能使用盒子比喻,而便签则指出了变量的正确工作方式。
示例 变量
a
和b
引用同一个列表,而不是那个列表的副本
>>> a = [1, 2, 3]
>>> b = a
>>> a.append(4)
>>> b
[1, 2, 3, 4]
如果把变量想象为盒子,那么无法解释 Python 中的赋值;应该把变量视作便利贴,这样示例中的行为就好解释了
刚刚我们说明了两个变量引用同一个数据的情况,再看一种情况:一个变量先后引用不同的数据
- 定义一个整数变量
a
,并且赋值为1
代码 | 图示 |
---|---|
a = 1 | ![]() |
- 将变量
a
赋值为2
代码 | 图示 |
---|---|
a = 2 | ![]() ![]() |
- 定义一个整数变量
b
,并且将变量a
的值赋值给b
代码 | 图示 |
---|---|
b = a | ![]() |
变量
b
是第 2 个贴在数字2
上的标签
如果变量已经被定义,当给一个变量赋值的时候,本质上是 修改了数据的引用
- 变量 不再 对之前的数据引用
- 变量 改为 对新赋值的数据引用
再看一看字典的例子:
>>> charles = {'name': 'Charles L. Dodgson', 'born': 1832}
>>> lewis = charles
>>> lewis is charles
True
>>> id(charles), id(lewis)
(4300473992, 4300473992)
>>> lewis['balance'] = 950
>>> charles
{'name': 'Charles L. Dodgson', 'balance': 950, 'born': 1832}
>>> alex = {'name': 'Charles L. Dodgson', 'born': 1832, 'balance': 950}
>>> alex == charles
True
>>> alex is not charles
True
charles 和 lewis 绑定同一个对象,alex 绑定另一个具有相同内容的对象
1.1.2. ==和is
== 运算符比较两个对象的值(对象中保存的数据),而 is 比较对象的引用(标识)。 通常,我们关注的是值,而不是标识,因此 Python 代码中 == 出现的频率比 is 高。
1.1.3. 函数的参数作为引用
Python 唯一支持的参数传递模式是共享传参(call by sharing)。
共享传参指函数的各个形式参数获得实参中各个引用的副本。也就是说,函数内部的形参是实参的别名。
这种方案的结果是,函数可能会修改作为参数传入的可变对象,但是无法修改那些对象的标识(即不能把一个对象替换成另一个对象)。下面示例中有个简单的函数,它在参数上调用 += 运算符。分别把数字、列表和元组传给那个函数,实际传入的实参会以不同的方式受到影响。
>>> def f(a, b):
... a += b
... return a
...
>>> x = 1
>>> y = 2
>>> f(x, y)
3
>>> x, y
(1, 2)
>>> a = [1, 2]
>>> b = [3, 4]
>>> f(a, b)
[1, 2, 3, 4]
>>> a, b
([1, 2, 3, 4], [3, 4])
>>> t = (10, 20)
>>> u = (30, 40)
>>> f(t, u)
(10, 20, 30, 40)
>>> t, u
((10, 20), (30, 40))
数字 x 没变。 列表 a 变了。 元组 t 没变。
数字的情况
相当于有隐含的代码 a=x b=y 函数调用结束后,a和b因为是临时变量,将不在指向数据1和2,但x,y依旧在引用着1和2,数据1和数据2因为还有变量在引用着自己所以并没有销毁
列表的情况
这里主要的区别之处在于
a += b
这行代码的不同。 因为数字是不可变变量,所以,a += b使得a指向了新的数据3; 而列表是可变变量,所以a += b的结果是就地修改列表,追加数据。
1.1.4. 可变和不可变类型
- 不可变类型,内存中的数据不允许被修改:
- 数字类型 int, bool, float, complex, long(2.x)
- 字符串 str
- 元组 tuple
- 可变类型,内存中的数据可以被修改:
- 列表 list
- 字典 dict
- 自定义类型(class定义的类型,后面讲到)
