介绍引用传递
python只允许使用引用传递
, 不存在其他语言中的值传递。引用传递即引用内存地址
, 无论是赋值还是函数调用。
不可变对象
不可变对象指向内存地址的值不能够被改变, 这些对象包含int,string,float,tuple
。
i = 1
j = i
print('id is %s for i' % id(i))
print('id is %s for j' % id(j))
print(i, j)
j = j + 1
print('id is %s for i' % id(i))
print('id is %s for j' % id(j))
print(i, j)
#result
id is 11061440 for i
id is 11061440 for j
1 1
id is 11061440 for i
id is 11061472 for j
1 2
- 最初 i 赋值给 j 时是
引用传递
, 它们的内存地址都是11061440, 即 i 和 j 指向同一个内存地址 - 后面当对象 j 被改变时, 由于所指向的内存中的值不能被改变, 所以会复制一份值到新的地址再处理计算(+1), 然后对象 j 指向新的地址11061472
可变对象
可变对象指向内存地址的值直接被改变, 这些对象包含list,dict,set
。
a = [1]
b = a
print('id is %s for a' % id(a))
print('id is %s for b' % id(b))
print(a, b)
b[0] = 0
print('id is %s for a' % id(a))
print('id is %s for b' % id(b))
print(a, b)
#result
id is 140198854737480 for a
id is 140198854737480 for b
[1] [1]
id is 140198854737480 for a
id is 140198854737480 for b
[0] [0]
- 最初 a 赋值给 b 时是
引用传递
, 它们的内存地址都是140198854737480, 即 a 和 b 指向同一个内存地址 - 后面当对象 b 被改变时, 由于所指向的内存中的值直接被改变, 发现改变b的同时a也被改变了, 但是 a 和 b 还是指向同一个内存地址
函数的参数传递也分可变和不可变对象的
def test_para(a, b):
a += 1
b[0] = 0
print('========1111111111==============')
print('a is %s and the id is %s.' % (a, id(a)))
print('b is %s and the id is %s.' % (b, id(b)))
a = 1
b = [1]
print('a is %s and the id is %s.' % (a, id(a)))
print('b is %s and the id is %s.' % (b, id(b)))
test_para(a, b)
print('========22222222222==============')
print('a is %s and the id is %s.' % (a, id(a)))
print('b is %s and the id is %s.' % (b, id(b)))
#result
a is 1 and the id is 11061440.
b is [1] and the id is 139909172055624.
========1111111111==============
a is 2 and the id is 11061472.
b is [0] and the id is 139909172055624.
========22222222222==============
a is 1 and the id is 11061440.
b is [0] and the id is 139909172055624.
- 当传过来的是
可变对象
,函数内部修改会影响
函数外部的可变对象。 - 当传过来的是
不可变对象
,函数内部修改不会影响
函数外部的不可变对象,因为修改的时候会先复制一份再修改
def test_para(b=[]):
b += [0]
print('b is %s and the id is %s.' % (b, id(b)))
test_para()
test_para()
test_para()
test_para([1, 2, 3])
#result
b is [0] and the id is 140394154311240.
b is [0, 0] and the id is 140394154311240.
b is [0, 0, 0] and the id is 140394154311240.
b is [1, 2, 3, 0] and the id is 140394177812936.
- Python 解释器执行 def 语句时, 会创建一个
函数对象
, 且只会有一个 - 默认参数 b 就已经计算出来, 指向了
[] 空列表
- 第一次调用test_para()时, 往b中添加一个值为1的元素
- 第二次,第三次调用test_para()时, 继续往b中添加一个值为1的元素,
用了同一个对象b, 指向同一个内存地址
- 当调用test_para([1, 2, 3])时, b 被
重新赋值
, b指向了[1, 2, 3]的新地址
list中的注意事项
- 对象被
重新赋值
a = a + [3] 或者 a = [3] 都是重新被赋值, 但是 a += [3]不是的,相当于a.extend([3])
a = b = [1, 2]
print(a, id(a), b, id(b))
a = a + [3]
print(a, id(a), b, id(b))
#result
[1, 2] 140607382289992 [1, 2] 140607382289992
[1, 2, 3] 140607405791752 [1, 2] 140607382289992
a = b = [1, 2]
print(a, id(a), b, id(b))
a += [3]
print(a, id(a), b, id(b))
#result
[1, 2] 140479908183624 [1, 2] 140479908183624
[1, 2, 3] 140479908183624 [1, 2, 3] 140479908183624
a = b = [1, 2]
print(a, id(a), b, id(b))
a = [3]
print(a, id(a), b, id(b))
#result
[1, 2] 139779074858568 [1, 2] 139779074858568
[3] 139779098360264 [1, 2] 139779074858568
a = [1, 2]
s = [a] * 2
print(s, id(s[0]), id(s[1]))
a.append(3)
print(s, id(s[0]), id(s[1]))
a[0] = 0
print(s, id(s[0]), id(s[1]))
s[0] = [0]
print(s, id(s[0]), id(s[1]))
#result
[[1, 2], [1, 2]] 139773557825096 139773557825096
[[1, 2, 3], [1, 2, 3]] 139773557825096 139773557825096
[[0, 2, 3], [0, 2, 3]] 139773557825096 139773557825096
[[0], [0, 2, 3]] 139773581326792 139773557825096
- 如何
复制list的值
,但不指向同一个地址
一阶列表
和高阶列表
有很大区别, 一阶列表可以使用a[:], list(a), a.copy(), copy.copy(a), copy.deepcopy(a)
等方法拷贝一份, 而高阶列表只能使用copy.deepcopy(a)
深度拷贝一份
import copy
a = [0, 1]
b = 3
num = [a, b]
print('num is %s and id is %s\n' % (num, id(num)))
c = num[:]
d = list(num)
e = num.copy()
f = copy.copy(num)
g = copy.deepcopy(num)
print('c is %s and id is %s\n' % (c, id(c)),
'd is %s and id is %s\n' % (d, id(d)),
'e is %s and id is %s\n' % (e, id(e)),
'f is %s and id is %s\n' % (f, id(f)),
'g is %s and id is %s\n' % (g, id(g))
)
print('-------------------------------------------')
a.append(2)
print('num is %s and id is %s\n' % (num, id(num)))
print('c is %s and id is %s\n' % (c, id(c)),
'd is %s and id is %s\n' % (d, id(d)),
'e is %s and id is %s\n' % (e, id(e)),
'f is %s and id is %s\n' % (f, id(f)),
'g is %s and id is %s\n' % (g, id(g))
)
#result
num is [[0, 1], 3] and id is 140319229340360
c is [[0, 1], 3] and id is 140319229131848
d is [[0, 1], 3] and id is 140319229219464
e is [[0, 1], 3] and id is 140319229219016
f is [[0, 1], 3] and id is 140319229219784
g is [[0, 1], 3] and id is 140319229220232
-------------------------------------------
num is [[0, 1, 2], 3] and id is 140319229340360
c is [[0, 1, 2], 3] and id is 140319229131848
d is [[0, 1, 2], 3] and id is 140319229219464
e is [[0, 1, 2], 3] and id is 140319229219016
f is [[0, 1, 2], 3] and id is 140319229219784
g is [[0, 1], 3] and id is 140319229220232