zoukankan      html  css  js  c++  java
  • Python学习笔记之函数参数传递 传值还是传引用

     

    在学完Python函数那一章节时,很自然的的就会想到Python中函数传参时传值呢?还是传引用?或者都不是? 

    在回答上面的问题之前我们先来看看下面的代码:

    代码1:

    def foo(var):
        var = 2
        print(var)  #output: 2
    a = 1
    foo(a)
    print(a)       #output: 1

    恩,看似是值传递
    代码2:

    def bar(var):
        var.append(1)
    
    b = []
    print(b) #output:[]
    bar(b)
    print(b) #output:[1]

    应该是引用传递?有点奇怪吧,为了弄清楚这个问题,我们先来了解一下Python中变量与对象的关系。

    一、变量和对象
    我们首先要知道Python中的“变量”与C/C++中“变量”是不同的。
    C/C++中,当你初始化一个变量时,就是声明一块存储空间并写入值。相当于把一个值放入一个盒子里:
    int a = 1;

    这里写图片描述

    现在a盒子里放了一个整数1,当给变量a赋另外一个值时会替换盒子a里面的内容:
    a = 2;

    这里写图片描述

    当你把变量a赋给另外一个变量时,会拷贝a盒子中的值并放入一个新的“盒子”里:
    int b = a;

    这里写图片描述这里写图片描述

    但是

    Python中,一个变量可以说是内存中的一个对象的“标签”或“引用”:
    a = 1

    这里写图片描述

    现在变量a指向了内存中的一个int型的对象(a相当于对象的标签)。如果给a重新赋值,那么“标签” a 将会移动并指向另一个对象:
    a = 2

    这里写图片描述

    原来的值为1int型对象仍然存在,但我们不能再通过a这个标识符去访问它了(当一个对象没有任何标签或引用指向它时,它就会被自动释放)。如果我们把变量a赋给另一个变量,我们只是给当前内存中对象增加一个“标签”而已:
    b = a

    这里写图片描述

    综上所述,在Python中变量只是一个标签,一个标识符,它指向内存中的对象。故变量并没有类型,类型是属于对象的,这也是Python中的变量可以被任何类型赋值的原因。

    二、可变对象与不可变对象
    Python的基本数据类型中,我们知道numbersstringstuples是不可更改的对象,而listdict是可以修改的对象。那么可变与不可变有什么区别呢?看下面示例:

    a = 1     # a指向内存中一个int型对象  
    a = 2     # 重新赋值  

    当将a重新赋值时,因为原来值为1的对象是不能改变的,所以a会指向一个新的int对象,其值为2。(如下面的图示)

    这里写图片描述

    示例2

    list1 = [1, 2]   # list1指向内存中一个list类型的对象  
    list1[0] = 2     # 重新赋值list1中第一个元素  

    因为list类型是可以改变的,所以第一个元素变更为2。更确切的说,list1的第一个元素是int型,重新赋值时一个新的int对象被指定给第一个元素,但是对于list1来说,它所指的列表型对象没有变,只是列表的内容(其中一个元素)改变了。如下图:

    这里写图片描述

    现在我们再来看看开始那两段代码:

    def foo(var):  
         var = 2 
         print(var)  
    
    a = 1  
    foo(a)    
    print(a)   

    上面这段代码把a作为参数传递给函数,这时avar都指向内存中值为1的对象。然后在函数中var = 2时,因为int对象不可改变,于是创建一个新的int对象(值为2)并且令var指向它。而a仍然指向原来的值为1int对象,所以函数没有改变变量a
    如下图:

    这里写图片描述

    代码2;

    def Bar(var):  
       var.append(1)  
    
    b = []  
    print(b)   
    Bar(b)  
    print(b)   

    这段代码把b传递给函数Bar,那么bvar都会指向同一个list类型的对象。因为list对象是可以改变的,函数中使用append在其末尾添加了一个元素,list对象的内容发生了改变,但是bvar仍然是指向这一个list对象,所以变量b的内容也发生了改变。
    如下图:

    这里写图片描述

    那么Python中参数传递是传值,还是传引用呢?准确的回答:都不是。之所以不是传值,因为没有产生复制,而且函数拥有与调用者同样的对象。而似乎更像是C++的传引用,但是有时却不能改变实参的值。所以只能这样说:对于不可变的对象,它看起来像C++中的传值方式;对于可变对象,它看起来像C++中的按引用传递。

     

    参考
  • 相关阅读:
    行为型模式续(中介者模式 + 解释器模式)
    行为型模式下<迭代器模式、访问者模式、备忘录模式>
    行为型模式中<职责链模式、状态模式、观察者模式>
    下载vuejs,Hello Vue(vscode)
    node.js运行配置(vs code非控制台输出)
    node.js环境配置(windows系统)
    玩转visual studio系列之类设计图
    xml基础之二(XML结构【2】)DTD文档模版
    xml基础之二(XML结构【1】)
    XML的基础之一(概念和语法)
  • 原文地址:https://www.cnblogs.com/JetpropelledSnake/p/9116923.html
Copyright © 2011-2022 走看看