首页 > 编程语言 >Python里参数是如何传递的?

Python里参数是如何传递的?

时间:2023-03-22 22:33:06浏览次数:55  
标签:变量 指向 Python 传递 对象 参数 l1 l2 my

如果接触过其他的编程语言,比如 C/C++,很容易想到,常见的参数传递有 2 种:值传递和引用传递。

所谓值传递,通常就是拷贝参数的值,然后传递给函数里的新变量。这样,原变量和新变量之间互相独立,互不影响。

所谓引用传递,通常是指把参数的引用传给新的变量,这样,原变量和新变量就会指向同一块内存地址。如果改变了其中任何一个变量的值,那么另外一个变量也会相应地随之改变。、

a = 1
b = a
a = a + 1

这里首先将 1 赋值于 a,即 a 指向了 1 这个对象,接着 b = a 则表示,让变量 b 也同时指向 1 这个对象。这里要注意,Python 里的对象可以被多个变量所指向或引用。最后执行 a = a + 1。需要注意的是,Python 的数据类型,例如整型(int)、字符串(string)等等,是不可变的。所以,a = a + 1,并不是让 a 的值增加 1,而是表示重新创建了一个新的值为 2 的对象,并让 a 指向它。但是 b 仍然不变,仍然指向 1 这个对象。因此,最后的结果是,a 的值变成了 2,而 b 的值不变仍然是 1。

通过这个例子可以看到,这里的 a 和 b,开始只是两个指向同一个对象的变量而已,或者也可以把它们想象成同一个对象的两个名字。简单的赋值 b = a,并不表示重新创建了新对象,只是让同一个对象被多个变量指向或引用。同时,指向同一个对象,也并不意味着两个变量就被绑定到了一起。如果给其中一个变量重新赋值,并不会影响其他变量的值。

l1 = [1, 2, 3]
l2 = l1
l1.append(4)
l1
[1, 2, 3, 4]
l2
[1, 2, 3, 4]

同样的,让列表 l1 和 l2 同时指向了 [1, 2, 3] 这个对象。由于列表是可变的,所以 l1.append(4) 不会创建新的列表,只是在原列表的末尾插入了元素 4,变成 [1, 2, 3, 4]。由于 l1 和 l2 同时指向这个列表,所以列表的变化会同时反映在 l1 和 l2 这两个变量上,那么,l1 和 l2 的值就同时变为了 [1, 2, 3, 4]。

l = [1, 2, 3]
del l

Python 里的变量可以被删除,但是对象无法被删除。del l 删除了 l 这个变量,从此以后你无法访问 l,但是对象 [1, 2, 3] 仍然存在。Python 程序运行时,其自带的垃圾回收系统会跟踪每个对象的引用。如果 [1, 2, 3] 除了 l 外,还在其他地方被引用,那就不会被回收,反之则会被回收。

由此可见,在 Python 中:

  • 变量的赋值,只是表示让变量指向了某个对象,并不表示拷贝对象给变量;而一个对象,可以被多个变量所指向。
  • 可变对象(列表,字典,集合等等)的改变,会影响所有指向该对象的变量。
  • 对于不可变对象(字符串,整型,元祖等等),所有指向该对象的变量的值总是一样的,也不会改变。但是通过某些操作(+= 等等)更新不可变对象的值时,会返回一个新的对象。
  • 变量可以被删除,但是对象无法被删除。

准确地说,Python 的参数传递是赋值传递 (pass by assignment),或者叫作对象的引用传递(pass by object reference)。Python 里所有的数据类型都是对象,所以参数传递时,只是让新变量与原变量指向相同的对象而已,并不存在值传递或是引用传递一说。

def my_func1(b):
    b = 2
 
a = 1
my_func1(a)
a
1

这里的参数传递,使变量 a 和 b 同时指向了 1 这个对象。但当执行到 b = 2 时,系统会重新创建一个值为 2 的新对象,并让 b 指向它;而 a 仍然指向 1 这个对象。所以,a 的值不变,仍然为 1。

不过,当可变对象当作参数传入函数里的时候,改变可变对象的值,就会影响所有指向它的变量。比如下面的例子:

def my_func3(l2):
    l2.append(4)
 
l1 = [1, 2, 3]
my_func3(l1)
l1
[1, 2, 3, 4]

这里 l1 和 l2 先是同时指向值为 [1, 2, 3] 的列表。不过,由于列表可变,执行 append() 函数,对其末尾加入新元素 4 时,变量 l1 和 l2 的值也都随之改变了。

但是,下面这个例子,看似都是给列表增加了一个新元素,却得到了明显不同的结果。

def my_func4(l2):
    l2 = l2 + [4]
 
l1 = [1, 2, 3]
my_func4(l1)
l1
[1, 2, 3]

要注意,这里 l2 = l2 + [4],表示创建了一个“末尾加入元素 4“的新列表,并让 l2 指向这个新的对象。这个过程与 l1 无关,因此 l1 的值不变。当然,同样的,如果要改变 l1 的值,就得让上述函数返回一个新列表,再赋予 l1 即可:

def my_func5(l2):
    l2 = l2 + [4]
    return l2
 
l1 = [1, 2, 3]
l1 = my_func5(l1)
l1
[1, 2, 3, 4]

要记住的是,改变变量和重新赋值的区别:

  • my_func3() 中单纯地改变了对象的值,因此函数返回后,所有指向该对象的变量都会被改变;
  • 但 my_func4() 中则创建了新的对象,并赋值给一个本地变量,因此原变量仍然不变。

至于 my_func3() 和 my_func5() 的用法,两者虽然写法不同,但实现的功能一致。不过,在实际工作应用中,我们往往倾向于类似 my_func5() 的写法,添加返回语句。这样更简洁明了,不易出错。

总结:

和其他语言不同的是,Python 中参数的传递既不是值传递,也不是引用传递,而是赋值传递,或者是叫对象的引用传递。需要注意的是,这里的赋值或对象的引用传递,不是指向一个具体的内存地址,而是指向一个具体的对象。

  • 如果对象是可变的,当其改变时,所有指向这个对象的变量都会改变。
  • 如果对象不可变,简单的赋值只能改变其中一个变量的值,其余变量则不受影响。

标签:变量,指向,Python,传递,对象,参数,l1,l2,my
From: https://www.cnblogs.com/wsmbszyn/p/17245741.html

相关文章

  • Python基础之sorted()函数用法
    1、简单的排序sorted函数可以对可迭代类型的容器内的数据进行排序lst1=(5,4,3,2,1)lst2=('F','D','Y','e','a','v')#字符串类型的排序按照ASCII的大小进行比较L1......
  • 升级/参数/连接/权限
    一.数据库升级1.环境说明:一般来说,MySQL数据库的二进制数据文件,也就是my.cnf中的配置项datadir所在的位置和我们MySQL应用程序安装的位置是分开的,仅仅通过配置项告诉MyS......
  • python if
    '''if判断语句'''age=18;age2=10;ifage>=18:print("成年人")'''if判断语句'''age=input("请输入你的年纪");ifint(age)<=18:print(f"你{age}......
  • 【Python】批量提取Fibersim xml文件中的节点网格数据
    程序功能:输入需求:fibersim导出的ply的xml文件,可以很多个也没问题。但名字要有规律,不然没法循环读写。比如我自己用的就是x1.xml、x2.xml、Y1.xml......的文件名定义......
  • 深入理解 Python 虚拟机:字典(dict)的实现原理及源码剖析
    深入理解Python虚拟机:字典(dict)的实现原理及源码剖析在本篇文章当中主要给大家深入介绍一下在cpython当中字典的实现原理,在本篇文章当中主要介绍在早期python3当中的......
  • python 中实现文件的复制
     001、(base)[root@PC1test3]#ls##测试数据及脚本a.txttest.py(base)[root@PC1test3]#cattest.py##复制程序importosos.popen('......
  • python中的pickle库
    1.1持久化模块pickle模块是Python专用的持久化模块,所谓的持久化就是让数据持久化保存,可以持久化包括自定义类在内的各种数据,比较适合Python本身复杂数据的存储。但是持久......
  • 构造函数中可以使用默认参数
    #include<iostream>usingnamespacestd;classBox{public: Box(intx=0,inty=0,intz=0); //声明构造函数时指定默认参数 voidarea(); voidvolume(); priva......
  • 通过MATLAB实现基于PSO优化的NARMAX模型参数辨识算法
    1.算法描述粒子群优化算法(PSO),粒子群中的每一个粒子都代表一个问题的可能解,通过粒子个体的简单行为,群体内的信息交互实现问题求解的智能性。最终算法伪代码如下:初始化:......
  • python表格处理--1
    importnumpyasnp#a=np.array([1,2,4,5])#创建一组数组#b=np.array([[1,2],[3,4],[5,6]])#创建二维数组#x=np.arange(5)#1个参数,起点取......