python3 參數(shù)中的陷阱,可變對象和不可變對象

介紹引用傳遞

python只允許使用引用傳遞, 不存在其他語言中的值傳遞。引用傳遞即引用內(nèi)存地址, 無論是賦值還是函數(shù)調(diào)用。

不可變對象

不可變對象指向內(nèi)存地址的值不能夠被改變, 這些對象包含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 時(shí)是引用傳遞, 它們的內(nèi)存地址都是11061440, 即 i 和 j 指向同一個(gè)內(nèi)存地址
  • 后面當(dāng)對象 j 被改變時(shí), 由于所指向的內(nèi)存中的值不能被改變, 所以會(huì)復(fù)制一份值到新的地址再處理計(jì)算(+1), 然后對象 j 指向新的地址11061472
    不可變對象

可變對象

可變對象指向內(nèi)存地址的值直接被改變, 這些對象包含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 時(shí)是引用傳遞, 它們的內(nèi)存地址都是140198854737480, 即 a 和 b 指向同一個(gè)內(nèi)存地址
  • 后面當(dāng)對象 b 被改變時(shí), 由于所指向的內(nèi)存中的值直接被改變, 發(fā)現(xiàn)改變b的同時(shí)a也被改變了, 但是 a 和 b 還是指向同一個(gè)內(nèi)存地址
    可變對象

函數(shù)的參數(shù)傳遞也分可變和不可變對象的

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.
  • 當(dāng)傳過來的是可變對象,函數(shù)內(nèi)部修改會(huì)影響函數(shù)外部的可變對象。
  • 當(dāng)傳過來的是不可變對象,函數(shù)內(nèi)部修改不會(huì)影響函數(shù)外部的不可變對象,因?yàn)樾薷牡臅r(shí)候會(huì)先復(fù)制一份再修改
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 解釋器執(zhí)行 def 語句時(shí), 會(huì)創(chuàng)建一個(gè)函數(shù)對象, 且只會(huì)有一個(gè)
  • 默認(rèn)參數(shù) b 就已經(jīng)計(jì)算出來, 指向了 [] 空列表
  • 第一次調(diào)用test_para()時(shí), 往b中添加一個(gè)值為1的元素
  • 第二次,第三次調(diào)用test_para()時(shí), 繼續(xù)往b中添加一個(gè)值為1的元素, 用了同一個(gè)對象b, 指向同一個(gè)內(nèi)存地址
  • 當(dāng)調(diào)用test_para([1, 2, 3])時(shí), b 被重新賦值, b指向了[1, 2, 3]的新地址

list中的注意事項(xiàng)

  • 對象被重新賦值
    a = a + [3] 或者 a = [3] 都是重新被賦值, 但是 a += [3]不是的,相當(dāng)于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
  • 如何復(fù)制list的值,但不指向同一個(gè)地址
    一階列表高階列表有很大區(qū)別, 一階列表可以使用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


最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容