Python函数的参数传递细节

article/2025/8/22 15:02:07

一、C/C++中的函数参数传递

  在C/C++的函数参数传递大家都很好理解,在定义时的参数就是形参,调用时输入的就是实参,下面用代码来理解值传递、地址传递(引用传递):

1.1 值传递

void find(int x){}
int z = 1;
y = find(z);

  在这个例子中,x是形参,z是实参,x变z不变。在值传递过程中,实参和形参位于内存中两个不同地址中,实参先自己复制一次拷贝,再把拷贝复制给形参。所以,在值传递过程中,形参的变化不会对实参有任何的影响。

1.2 地址传递(引用传递)

void find(int &x){}
int a = 3;
int &z = a;
y= find(z)

  在这个例子中,x是形参,z是实参。但z随x而改变。在函数调用的时候,实参传递给函数的是指针地址,地址一样也就意味着实参和形参是一样的,当你的形参发生改变时,实参也会发生改变。(即形参和实参都指向同一个值,当值变化了,那么形参和实参也就都变化了)

二、Python中的函数参数传递

  在 C/C++ 中,传值和传引用是函数参数传递的两种方式,那么在Python中参数是如何传递的?为了回答这个问题,首先先看一段代码:

def fun1(arg):arg = 2print(arg)a = 1
fun1(a)  # 输出:2
print(a) # 输出:1

  看到这个结果,貌似可以下结论了,是值传递稳了!但是,我们再看一段代码:

def fun2(args):args.append(1)list1 = []
print(list1 )# 输出:[]
fun2(list1)
print(list1) # 输出:[1]

  有人看到这里就开始凌乱了,这什么情况。。。我们再看一段代码:

def fun2(args):args.append(1)list1 = []
print(id(list1)) # 输出:4324106952
fun2(list1)
print(id(list1))  # 输出:4324106952

  看到这里,有人会问了,参数传递到底是传值还是传引用或者两者都不是?
  在Python中,要解释函数是什么传递就得先了解Python的一个特殊机制:可变对象和不可变对象。

2.1 可变对象和不可变对象

  Python在heap中分配的对象分成两类:可变对象和不可变对象。所谓可变对象是指,对象的内容可变,而不可变对象是指对象内容不可变。

  不可变(immutable):int、字符串(string)、float、(数值型number)、元组(tuple)
  可变(mutable):字典型(dictionary)、列表型(list)
  下面通过几个例子来理解:

i = 73
i += 2

在这里插入图片描述
  因为int类型是不可变对象,所以当执行+2操作时,其实是把73扔了,再在内存重新创建一个75,用i指向它。

>>>x = 1
>>>y = 1
>>>x = 1
>>> x is y
True
>>>y is z
True

  如上所示,因为整数为不可变,x,y,z在内存中均指向一个值为1的内存地址,也就是说,x,y,z均指向的是同一个地址,值得注意的是,整形来说,目前仅支持(-1,100)。
  总结一下不可变对象的优缺点。优点是,这样可以减少重复的值对内存空间的占用。缺点呢,我要修改这个变量绑定的值,如果内存中没用存在该值的内存块,那么必须重新开辟一块内存,把新地址与变量名绑定。而不是修改变量原来指向的内存块的值,这会给执行效率带来一定的降低。
  下面看一个可变对象的例子:

m=[5,9]
m+=[6]

在这里插入图片描述
  如上所示,可变对象的特点就是,当对可变对象进行修改时,不用重新开辟内存等操作,而是直接进行内容修改。

2.2 Python的变量与对象

  有了上面的基础,可以理解,在Python中的一切皆为对象,数字是对象,列表是对象,函数也是对象,任何东西都是对象。而变量是对象的一个引用(又称为名字或者标签,对象的操作都是通过引用来完成的。

a = []	# []是一个空列表对象,变量a是该对象的一个引用。
a.append(1)

  在 Python 中,“变量”更准确叫法是“名字”、“标签”,赋值操作“=”就是把一个名字绑定到一个对象上。就像给对象添加一个标签。

a = 1	# 整数 1 赋值给变量 a 就相当于是在整数1上绑定了一个 a 标签。
a = 2	# 整数 2 赋值给变量 a,相当于把原来整数 1 身上的 a 标签撕掉,贴到整数 2 身上。
b = a	# 把变量a赋值给另外一个变量b,相当于在对象2上贴了a,b 两个标签,通过这两个变量都可以对对象2进行操作。

  变量本身没有类型信息,类型信息存储在对象中,这和C/C++中的变量有非常大的出入(C中的变量是一段内存区域)

2.3 Python的函数参数传递

  最后就可以彻底理解Pyhton的参数传递原理了,Python 函数中,参数的传递本质上是一种赋值操作,而赋值操作是一种标签到对象的绑定过程,清楚了赋值和参数传递的本质之后,我们再来看几段代码:

def fun(arg):arg = 2print(arg)a = 1 
fun(a)  # 输出:2
print(a) # 输出:1

  整个过程描述:一个数字对象1,一个标签a指向了数字对象1。进入fun函数时,a标签赋值给了arg标签,也就是说此时arg标签和a标签同时指向数字对象1。然后arg标签又指向了数字对象2,此时a标签和arg标签的指向不一样了,print(arg)输出的是arg标签指向的数字对象,即输出2。最后print(a)输出的是a标签指向的数字对象1,即输出1。
在这里插入图片描述
  我们来看第二段代码:

def fun(args):args.append(1) b= []
print(b)# 输出:[]
print(id(b)) # 输出:4324106952
fun(b)
print(b) # 输出:[1]
print(id(b))  # 输出:4324106952

  整个过程描述:一个list对象[],一个标签b指向该对象。进入fun函数时,b标签赋值给了args标签,也就是说此时args标签和b标签同时指向list对象[]。然后args标签执行了args.append(1),即list对象[]添加了一个元素1,此时执行print(b),输出[1],原因在于b和args指向同一个list对象,list对象改变,那么通过相同指向的不同标签访问对象得到同一个输出。
在这里插入图片描述

2.3 Python参数传递总结

  最后,回到问题本身,即python函数究竟是是传值还是传引用呢?说传值或者传引用都不准确。非要安一个确切的叫法的话,叫传对象(call by object)。下面来一段坑人代码来进一步说明总结:

def bad_append(new_item, a_list=[]):a_list.append(new_item)return a_list

  为什么说坑人呢,因为同样的调用会带来不一样的结果:

>>> print(bad_append('one'))
['one']>>> print(bad_append('one'))
['one', 'one']

  分析:当第一次调用时,由于python机制原因,创建了一个list对象[],并用标签a_list指向,执行a_list.append(new_item)使得a_list指向的list对象[]添加了一个字符串’one’,然后返回a_list标签,执行输出print(bad_append(‘one’))就是print(a_list),输出a_list指向的对象[‘one’]。
  第二次调用时,由于list对象是可变对象,所以在执行a_list=[]时并没有创建新的list对象[],而是和第一次执行函数时用的同一个list对象,所以此时的a_list指向的是[‘one’],所以在执行a_list.append(new_item)后会返回[‘one’, ‘one’]。
在这里插入图片描述
  那么,我们要怎么修改这个函数来达到预定目的呢,很简单,就是把可变对象改成不可变对象即可。

def good_append(new_item, a_list=None):if a_list is None:a_list = []a_list.append(new_item)return a_list

  None是 NoneType 类的对象,并且无法修改它的值。所以每次调用函数时a_list都是指向新的None对象。
在这里插入图片描述

三、总结

  学习一门新语言时,不要总是根据已有的语言经验来代入,要深入了解新语言的特殊机制,才能避免出现太多的bug。


http://chatgpt.dhexx.cn/article/GLnTPo2R.shtml

相关文章

python中参数传递

在编程语言中,函数的参数传递有两种情况: 按值类型传递 num 10 def double(arg):argarg*2print(arg)double(num)调用该函数,传入一个变量,其实传入的是该变量的一个副本,该变量在函数中发生变化,不影响函…

Python参数的传递

一、参数的传递 函数的参数传递本质上就是:从实参到形参的赋值操作。Python中“一切皆对象”,所有的赋值操作都是“引用的赋值”。所以,Python中参数的传递都是“引用传递”,不是“值传递”。 具体操作时分为两类: …

python传参数的方法

Python的参数传递是通过传参指针来完成的,当参数指针指向了另一个变量时,它就会被传递给它。这种传递方式与 Java或C#中的传参方式是类似的,在 Python中,参数可以是一个字符串,也可以是一个对象。这个方法的好处是它不…

python中参数的传递

一、函数的参数传递本质上就是∶从实参到形参的赋值操作。Python中“一切皆对象”,所有的赋值操作都是‘引用的赋值”。所以,Python中参数的传递都是“引用传递”,不是“值传递”。具体操作时分为两类︰ 1.对“可变对象”进行“写操作”&…

Python函数参数传递

Python函数参数传递 一、前言二、了解形式参数和实际参数1.通过作用理解2.通过比喻来理解形参和实参 三、位置参数1.数量必须与定义时一致2.位置必须与定义时一致 四、关键字参数五、为参数设置默认值六、可变参数1.*parameter2.**parameter 一、前言 在调用函数时,…

计算机毕业论文外文翻译是什么,毕业论文的外文翻译是什么

毕业论文的外文翻译是什么 此栏目涵盖有关于外文翻译和毕业论文的范例,免费给你学论文的外文翻译是什么提供有关参考资料。 摘要:文章从成人学生知识基础、指导教师、写作过程监控等方面,分析了成人高校学生在毕业论文写作中存在的伪造、抄袭、专业水平低…

关于android的外文论文,毕业论文外文翻译-Android开发

毕业论文外文翻译-Android开发 (11页) 本资源提供全文预览,点击全文预览即可全文预览,如果喜欢文档就下载吧,查找使用更方便哦! 9.90 积分 毕业设计(论文)外文翻译 毕业 论文题目 基于 Android 手机通讯录的设计与实现 作 者 姓 名 所学专业…

在哪能查到英文论文?

不论是撰写英文论文还是引用外文文献,写论文的过程中想必缺不了检索合适的英文论文这个步骤,在本篇内容里,不仅教会你如何查到英文论文,还要教会你怎么样快速找到合适的英文论文!听起来是不是令人心驰神往,…

计算机毕业论文外文译文,计算机毕业论文外文文献译文

计算机毕业论文外文文献译文 外文文献原文What is ASP.NET? ASP.NET is a programming framework built on the common language runtime that can be used on a server to build powerful Web applications. ASP.NET offers several important advantages over previous Web…

如果想要直到一篇外文论文的质量

首先在CCF A类中寻找 然后view这篇论文,然后点击这篇论文所属的期刊名称2处 就可以看到引用得分和影响因子了,3处 文献鸟自动推送:https://www.storkapp.me/main.php 文献鸟使用的教学视频:https://www.bilibili.com/video/BV1tf4…

关于php的外文论文,php毕业设计外文翻译--通过PHP访问MySQL(适用于毕业论文外文翻译+中英文对照).doc...

[摘要]PAGE 原文:? ? Getting PHP to Talk to MySQl Now that you’re comfortable using the MySQL client tools to manipulate data in the database, you can begin using PHP to display and modify data from the database. PHP has standard functions for…

都有哪些查找和下载英文文献的方法?

很多朋友在查找文献的时候,都不知道该从哪里找,也不知道从哪里下载,怎么下载,尤其是想要查找英文文献。其实查询和下载英文文献无非以下三种方式: 选择一些比较权威,内容丰富,基本覆盖所有学科…

面向对象实现游戏聊天中的敏感词屏蔽功能,将敏感词汇用星号***替换

import java.util.Scanner;//新建一个类 public class Replace {// 定义一个字符串String commons;// 建一个替换的方法public void replace() { //控制台输入Scanner sc new Scanner(System.in);// 提示输出(为方便功能实现,此处提示内定的敏感词汇&am…

腾讯敏感词汇大全_腾讯数平精准推荐 | OCR技术之识别篇

腾讯数平精准推荐(Tencent-DPPR)团队一直致力于实时精准推荐、海量大数据挖掘等领域的技术研发与落地。 在社交广告推荐领域,团队自研的深度在线点击率预估算法及全流程实时推荐系统,持续多年提升社交广告点击率。图像作为当前社交广告最重要的展示形式,文字识别、物体识别等…

小程序中关于敏感词汇检测

小程序审核增加敏感词汇校验,避免违法违规而被停用服务或者投诉。 本文例子引用的百度AI开发者提供的API: 链接位置:https://console.bce.baidu.com/ai/#/ai/ocr/overview/index 创建应用后生成应用对应的id和key 应用到小程序中,&#xff…

Python 如何检测敏感词汇

设计思路:根据敏感词库文件筛选,查看输入的文本中是否包含敏感词汇。从而过滤出相关的敏感词。 【阅读全文】 导入应用相关的模块。 import os import logging import sys导入UI界面相关的模块。 from PyQt5.QtWidgets import QApplication,QWidget,…

敏感词汇工具类sensitive word的使用及详解

简述: 1.平时工作中,只要涉及到用户可以自由发言(博客、文档、论坛),就要考虑内容的敏感性处理,sensitive word工具是一个快速的敏感词过滤工具,基于 DFA 算法实现的高性能敏感词工具(mirrors / houbb / s…

Python敏感词汇检测

只要思想不滑坡,办法总比困难多 昨天在写练习题的时候写到这点特别迷,一直绕不过这个弯,最后也算是成功实现吧,记录一下,防止下次再绕的出不来。 之前访问的的Github镜像站一直触发滥用检测机制,着实很烦…

敏感词汇检测

1、今天做测试的时候抓到一个数据包,发现一个txt文件(CensorWords.b7e4bfb.txt),第一眼反应以为是系统被入侵了,被入侵者传了个txt到服务器上面,后面发现不对啊,攻击的话也不应该上传这种txt&am…