美文网首页我的Python之旅
对Python函数传参的一些思考

对Python函数传参的一些思考

作者: resolvewang | 来源:发表于2018-06-22 10:33 被阅读28次

    今天看到这样一个问题: Python 的函数是怎么传递参数的,有了一些兴趣,因为以前都是直接信的一个流传度较广的说法

    对于不可变对象作为函数参数,相当于C系语言的值传递;
    对于可变对象作为函数参数,相当于C系语言的引用传递。

    那么事实上真是如此吗?我们来看几个例子。

    首先我们来看看第一个说法,这里我实验环境是Python3.6。

    对于不可变对象作为函数参数进行传递,这里我分别以inttuple进行测试

    def test_immutable_for_simpledata(args):
        print('============')
        print(2, id(args))
        args = args + 10
        print(3, args)
        print(4, id(args))
        print('============')
    
    
    if __name__ == '__main__':
        cur = 5000
        print(1, id(cur))
        test_immutable_for_simpledata(cur)
        print(5, cur)
        print(6, id(cur))
    

    结果如下

    1 42301856
    ============
    2 42301856
    3 5010
    4 42301616
    ============
    5 5000
    6 42301856
    

    我们看第一步和第二步,两者打印出来的地址是一样的,这可以证明Python对不可变类型传参是使用的引用传参,但是为什么函数中用了args+10,函数外面的args值还是没变呢?我们可以看到第四步的args的地址其实已经变了。即说明加10和未加10两个时间点是两个不同的对象。为什么是这样呢?这就需要理解什么是不可变对象了。在我理解来,不可变对象就是它的成员元素不变,比如对于简单对象(如int,float)来说,就是它的值不变,对于复合类型(如tuple)来说,就是它的成员元素(即地址)不变。回到代码中,这里是基本类型的不可变对象,对它进行运算操作其实就是创建新的对象,然后将原先的变量名绑定到新的对象上。读者前一句话没读懂的话,可以去了解一下Python的名字空间。

    为了加深读者的理解,我们再以tuple为例进行测试。代码如下

    def test_immutable_for_tuple(args):
        print('============')
        print(2, id(args))
        args[0].append(5)
        print(3, args)
        print(4, id(args))
        print('============')
    if __name__ == '__main__':
        cur = ([0], 1)
        print(1, id(cur))
        test_immutable_for_tuple(cur)
        print(5, cur)
        print(6, id(cur))
    

    结果如下

    1 33951020
    ============
    2 33951020
    3 ([0, 5], 1)
    4 33951020
    ============
    5 ([0, 5], 1)
    6 33951020
    

    这次的结果和上次明显不同了。虽然tuple是不可变对象,我们使用tuple为参数传入函数中,然后对tuple中的列表元素进行了操作,结果函数外部的变量也发生了变化。我们也可以看到参数的地址在函数内外其实都一样。

    根据上述测试,我们可以得出一个结论,对于不可变对象的函数传参,依然是传的引用(地址)。对于简单类型,在函数内对其操作之所以不会影响函数范围外的值,是因为运算中的赋值操作产生了新的对象,而不是对原有对象的改变。而对于一些复杂类型,就可以比较清晰的看出,函数内参数的改变同样会影响函数外的变量。

    对于可变对象,我们同样可以使用上述逻辑去验证,由于篇幅,我就不啰嗦了。

    最终可以得到的结论是,Python中的函数通过引用传参。

    相关文章

      网友评论

        本文标题:对Python函数传参的一些思考

        本文链接:https://www.haomeiwen.com/subject/majcyftx.html