当前位置: 首页 > article >正文

Python中传参是按值传递还是按引用传递?

在Python中,关于参数传递的方式,常常会引起一些混淆。实际上,Python中的参数传递方式既不是纯粹的“按值传递”(pass-by-value),也不是传统意义上的“按引用传递”(pass-by-reference)。更准确地说,Python采用的是“按对象引用传递”(pass-by-object-reference)的方式。这种方式在处理不同类型的对象(特别是可变对象和不可变对象)时表现出不同的行为特性。

一、按对象引用传递的理解

在Python中,所有的变量都是对对象的引用,而不是对象本身。当我们将一个变量作为参数传递给函数时,我们实际上是传递了这个变量的引用(即对象的内存地址),而不是对象本身的值或拷贝。这意味着,如果函数内部对这个引用所指向的对象进行了修改(且该对象是可变的),那么这些修改会影响到原始对象。然而,如果函数内部尝试“修改”一个不可变对象(如整数、浮点数、字符串、元组等),由于这些对象的不可变性,实际上是在创建一个新的对象,并将引用指向这个新对象,而不会影响到原始对象。

二、不可变对象的参数传递

对于不可变对象(如整数、浮点数、字符串、元组等),当我们将它们作为参数传递给函数时,虽然在函数内部看起来像是可以直接修改这些对象,但实际上Python会创建这些对象的一个“拷贝”的引用(注意,这里的“拷贝”引用仅指操作层面上的,由于对象的不可变性,这种“拷贝”在大多数情况下是无关紧要的)。然而,由于这些对象是不可变的,任何试图修改它们的操作都会导致创建一个新的对象,并将引用重新指向这个新对象,而不会影响到原始对象。

示例

def modify_string(s):
s = s + "world" # 这里的s是一个新的字符串对象
print("Inside function:", s)
original_string = "hello"
modify_string(original_string)
print("Outside function:", original_string) # 输出仍然是"hello"

在这个例子中,尽管我们在函数内部修改了s的值,但原始字符串original_string并没有改变。这是因为字符串是不可变的,当我们执行s = s + "world"时,Python实际上创建了一个新的字符串对象,并将s指向这个新对象。原始的字符串对象("hello")并没有受到影响。

三、可变对象的参数传递

对于可变对象(如列表、字典、集合等),当我们将它们作为参数传递给函数时,传递的是这些对象的引用(即内存地址的引用)。这意味着函数内部对这些对象的修改会影响到原始对象,因为函数内部和外部都是引用同一个对象。

示例

def modify_list(lst):
lst.append(4) # 直接修改了lst引用的列表对象
print("Inside function:", lst)
original_list = [1, 2, 3]
modify_list(original_list)
print("Outside function:", original_list) # 输出[1, 2, 3, 4],列表被修改了

在这个例子中,我们直接修改了函数内部lst引用的列表对象。由于列表是可变的,并且我们传递的是列表的引用,所以原始列表original_list也被修改了。

四、深入理解按对象引用传递

虽然Python中的参数传递方式通常被描述为“按对象引用传递”,但这并不意味着Python在处理参数时涉及到传统意义上的指针操作。Python的引用机制更为高级和抽象,它隐藏了指针的复杂性,使得程序员可以更加专注于问题的本质,而不是底层的内存管理。

此外,需要注意的是,即使Python是通过引用传递对象,但在某些情况下,我们仍然可以通过创建新对象来实现“按值传递”的效果。例如,对于不可变对象,尽管我们不能直接修改它们,但可以通过重新赋值变量来改变引用的对象。而对于可变对象,如果我们希望在函数内部修改对象而不影响原始对象,我们可以使用copy模块的copy()deepcopy()函数来创建对象的浅拷贝或深拷贝。

五、结论

综上所述,Python中的参数传递方式是通过对象的引用进行的。对于不可变对象,这种传递方式在大多数情况下表现得像“按值传递”,因为不可变对象的值不能被修改。而对于可变对象,这种传递方式则表现得像传统意义上的“按引用传递”,因为函数内部和外部都可以修改同一个对象。然而,需要注意的是,Python的引用传递并不涉及传统的指针操作,而是一种更为高级和抽象的引用机制。


http://www.kler.cn/a/288027.html

相关文章:

  • 【route】route add命令详解
  • 【eNSP】路由基础与路由来源——静态路由实验
  • 在 Oracle Linux 8.9 上安装Oracle Database 23ai 23.5
  • 【智能电视??】关于电视、以及IPTV 和OTT TV区别(了解)
  • linux常见资源查询命令(持续更新)
  • java面试题(jvm)
  • GO、KEGG等富集棒棒图
  • 为了支持XR,3GPP R18都做了哪些增强?
  • Spring源码(9)--FactoryBean简介
  • Prometheus 学习笔记
  • vscode自动添加python文件的头部注释
  • Jenkins+docker+springboot 一键自动部署项目步骤
  • 代码随想录刷题记录(七)——二叉树(2)
  • WordShield 一款轻量级且灵活的敏感词过滤库
  • 【论文阅读】语义通信安全研究综述(2024)
  • Xinstall赋能,H5与App完美融合,打造极致用户体验
  • 关于武汉芯景科技有限公司的多协议收发芯片XJ3160开发指南(兼容MAX3160)
  • react 样式和vue样式的区别
  • Fabric.js TextBox揭秘:splitByGrapheme属性实现文本自然换行
  • Android使用IntentService
  • JavaScript初级——Navigatior
  • 《从C/C++到Java入门指南》- 25.final 关键字
  • 跨地域工作利器:深度解析2024年远程控制软件的新特性
  • 力扣SQL仅数据库(1068~1084)
  • 做数据爬虫工作:是否需要准备单独的IP库和爬虫库?
  • ADAS---基于检测框的单目测距方法