python3 参数中的陷阱,可变对象和不可变对象

介绍引用传递

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


最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,657评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,662评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,143评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,732评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,837评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,036评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,126评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,868评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,315评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,641评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,773评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,470评论 4 333
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,126评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,859评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,095评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,584评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,676评论 2 351