记住函数传参既不是传值也不是传引用

Python中函数传值到底是传值还是传引用呢?下面逐一讨论主流的3个观点:传引用传值可变对象传引用,不可变对象传值

传引用

def inc(num):
    print(id(num))
    num += 1
    print(id(num))


num = 21
print(id(num))  # 1628139152

inc(num)

# 1628139152
# 1628139184

print(num)  # 21

从输出结果来看num的值还是不变,但id(num)的值在函数体前后却不一致。显然,传引用这个说法是不恰当的。

传值

def change_value(alpha):
    print("Before value: ", alpha)
    beta = alpha
    alpha.append('N')
    print("After value: ", beta)
    return beta


cur = ['B', 'A', 'T']
res = change_value(cur)

# Before value:  ['B', 'A', 'T']
# After value:  ['B', 'A', 'T', 'N']

print(res)  # ['B', 'A', 'T', 'N']
print(cur)  # ['B', 'A', 'T', 'N']

传值通俗来讲就是这个意思:你在内存中有一个位置,我也有一个位置,我把我的值复制给你,以后你做什么就跟我没关系了,我是我,你是你,咱俩井水不犯河水。

可上面的程序输出根本不是这么一回事,显然change_value()函数没有遵守约定,调用该函数之后cur也发生了变化,这明显侵犯了cur的权利。这么看来传值这个说法也不合适。

可变对象传引用,不可变对象传值

def change_element(old):
    print(id(old))
    new = old
    print(id(new))
    if len(old) > 5:
        new = ['a', 'b', 'c']
    for idx, value in enumerate(new):
        if isinstance(value, list):
            new[idx] = '***'

    print(new)
    print(id(new))


test_one = [20, 19, ['J', 5], [2, 2]]   # test_one的元素个数小于5
change_element(test_one)

# 2102250550920
# 2102250550920
# [20, 19, '***', '***']
# 2102250550920

print(test_one)     # [20, 19, '***', '***']


test_two = [2, 0, 1, 9, ['J'], 22]      # test_two的元素个数小于5
change_element(test_two)

# 1885767382408
# 1885767382408
# ['a', 'b', 'c']
# 1885767382664

print(test_two)     # [2, 0, 1, 9, ['J'], 22]

对于test_one、new和old的表现和我们理解的传引用确实一致,最好test_one被修改为[20, 19, '***', '***'],但对于输入test_two、new和old的id输出在进行列表相关的操作前是一致的,但操作之后new的id值却变了,整个test_two在调用函数change_element()后却没有发生任何变化,可是按照传引用的理解期望输出应该是['a', 'b', 'c'],似乎可变对象传引用这个说法也不恰当。

Python函数中参数传递的机制

对于如下语句分析在C/C++以及Python中是如何赋值的:

a = 5
b = a
b = 7

C/C++中当执行b=a的时候,在内存中申请一块内存并将a的值复制到该内存中,当执行b=7之后是将b对应的值从5修改为7。但在Python中赋值并不是赋值,b=a操作使得b与a引用同一个对象。而b=7则是将b指向对象7。

a = 5
print(id(a))    # 1627286672

b = a   # 传递的是对象的引用
print(id(b))    # 1627286672

b = 7
print(id(b))    # 1627286736
print(id(a))    # 1627286672

**Python函数参数传值是传对象(call by object)或者说传对象的引用(call-by-object-reference)。**函数参数在传递的过程中将整个对象传入,对可变对象的修改在函数外部以及内部都可见,调用者和被调用者之间共享这个对象,而对于不可变对象,由于并不能真正被修改,因此修改往往是通过生成一个新对象然后赋值来实现的。

(最近更新:2019年05月22日)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值