在c 中,我们知道函数参数可以传值,也可以传引用。在python中函数参数到底如何传递的呢?
在python函数中,为什么我们传入一个列表会导致原来一个列表也发生改变呢?
代码语言:javascript复制def fun(a):
a = [4]
l1 = [1, 2, 3]
fun(l1)
print(l1) # [1, 2, 3, 4]
要解决上述问题,我们需要先复习下面的一些知识
代码语言:javascript复制# 例1
a = 1
b = 1
print(id(a)) # 140710599762336
print(id(b)) # 140710599762336
print(id(1)) # 140710599762336
# id() 获取对象的地址 这里我们可以发现变量a,b地址是一样的。
# 通俗得讲
# "=" 右边1看做一个对象,a贴对象1,b也贴对象1。
# 那么a,b两个变量贴着同一个对象1,则他们的地址也一致
代码语言:javascript复制# 例2
a, b = 1, 2 # 此时变量a贴对象1,变量b贴对象2
print(id(a), id(1)) # 140710620012960 140710620012960
print(id(b), id(2)) # 140710620012992 140710620012992
a, b = b, a # 等号右边b相对于对象2,a相当于对象1 等号左边a贴2,b贴1
print(id(a), id(2)) # 2 140710620012992 140710620012992
print(id(b), id(1)) # 1 140710620012960 140710620012960
# 现在明白为什么python可以直接两个变量交换了吧,实际上是对象赋给
代码语言:javascript复制# 例3
a = 1
print(a, id(a)) # 1 140710599762336
a = a 1
print(a, id(a)) # 2 140710599762368
# 这个容易理解,为什么a变为2,且id变化了
# 因为"="右边 a 1 生成一个新的对象2,且把新的变量a贴到对象2上
b = [1, 2, 3]
print(b, id(b)) # [1, 2, 3] 2116038381960
b = [4]
print(b, id(b)) # [1, 2, 3, 4] 2116038381960
# 为什么 b =[4]后 b的id没有变化呢。 因为b最开始贴的对象[1,2,3]
# 由于我们知道python中列表是可变对象
# b = [4] 实际上是对象[1,2,3]本身添加了[4],并没有生成新的对象,则b的id没有发生变化
c = [1, 2, 3]
print(c, id(c)) # [1, 2, 3] 2116038382472
c = c [4]
print(c, id(c)) # [1, 2, 3, 4] 2116039760392
# 为什么 c = c [4]后 c的id变化了。因为c [4]会生成一个新的对象,再用c贴新的对象
# 补充: = 操作调用 __iadd__方法,没有该方法时,再尝试调用__add__方法
# __iadd__方法直接在原对象上进行更新
# __add__方法会返回一个新的对象,原对象不修改
# 对于不可变对象,没有 __iadd__方法,所以 =和 的效果是一样的,因为调的都是 __add__ 方法
# 可变对象(列表,字典,集合等等)
# 不可变对象(字符串、整型、元组等等)
# 如果对象是可变的,当其改变时,所有指向这个对象的变量都会改变。
# 如果对象不可变,简单的赋值只能改变其中一个变量的值,其余变量则不受影响。
代码语言:javascript复制# 例4 提问
a = [1, 2, 3]
b = [a, 4, 5]
# 此时分别执行 a = a [4] a = [4] b有什么变化?
Python 函数的参数传递
参数传递时,只是让新变量与原变量指向相同的对象。可以理解为是对象的引用传递。
我们现在回过头来看文章开头的问题
代码语言:javascript复制def fun(a):
a = [4]
l1 = [1, 2, 3]
fun(l1) # 把对象[1,2,3]传递进去,经过 a =[4] 此时旧对象本身变为[1,2,3,4] 并不是生成新对象
print(l1) # [1, 2, 3, 4]
# 对比下面两个例子
def fun2(a):
a.append(3) # append在原本对象后面添加元素,并不会生成新对象
l2 = [1, 2]
fun2(l2)
print(l2) # [1, 2, 3]
def fun3(a):
a = a [5] # 生成新对象,原本对象[1,2,3,4]并没发生改变
l3 = [1, 2, 3, 4]
fun3(l3)
print(l3) # [1, 2, 3, 4]