一、前言
在python中,函数参数的定义和传递有以下几种方式:
语法
意义
def func(name)
普通参数,可以根据位置匹配,也可以根据key来匹配
def func(name=value)
默认参数,当参数没有传递时,使用默认值
def func(*iteratable)
将所有剩下的未匹配的参数收集至一个tuple中
def func(**dictionary)
将剩下未匹配的参数收集值一个dict中
def func(*, name)
必须使用key来匹配参数
def func(*other, name)
必须使用key来匹配参数
func(value)
函数调用,参数值按传递的参数顺序匹配
func(name=value)
函数调用,参数值根据key来匹配
func(*iteratable)
函数调用,将iteratable容器中的参数展开,按位置匹配对应的函数参数
func(**dictionary)
函数调用,将dict中的参数展开,按key值来匹配对应的函数参数

在python中,参数可以按照顺序传递,在调用函数时,参数的值按照传递的顺序,从左到右依次匹配。并且还可以给参数传递默认值,这都很好理解,因为在C、C++、Java等许多语言中,函数的参数传递都是按照这种方法来传递的。

但python的参数定义和传递除了按照顺序传递以及可以给默认值外,它还有其它的一些特点,在进一步讲解之前,首先说明python中函数调用中参数匹配的顺序:
  • 按照顺序,给没有key的参数赋值,意味着传递参数时,需按顺序匹配的参数必须出现在按key匹配的参数之前;
  • 给按照key匹配的参数赋值;
  • 将多余的按照顺序匹配但未匹配的参数值归入*name的tuple中;
  • 将多余未匹配上的按照key进行匹配的参数值归入**name的dict对象中;
  • 将为匹配上的且具有默认值的参数赋默认值
二、按key匹配参数
对于C、C++这种语言,在调用函数时,系统会首先将函数地址压入堆栈,其次按参数的从右往左的顺序,一次压入堆栈。因此,C、C++这种语言它们只支持按顺序匹配形参。而python的做法不同,参数除了可以按顺序匹配,还可以按照参数名称来匹配。如:
def func(name, age):
print(name, age)
对于这个函数,以下的调用时等价的:
func('rechar', 27)    #按顺序匹配
func(name = 'rechar', age = 27)    #按参数名称匹配,在运行时告诉系统参数name的值为‘rechar’,age的值为27
func(age = 27, name = 'rechar')    #按参数名称匹配
func('rechar', age = 27)    #name是按顺序匹配,age按名称匹配
在python中,当按照参数名称进行匹配参数是,参数传递的顺序是可以任意的,不要求按照函数定义中参数的顺序进行传递。在使用名称匹配时,如果需要混合使用按顺序匹配规则,则按顺序匹配的参数必须出现在按key匹配的参数前,否则会报错:
func(name = 'rechar', 27)
以上调用会报如下错误:
三、函数定义中的”*name“
python在给按顺序匹配和按key匹配的参数赋完值后,如果发现调用者传入的参数仍有未匹配上的会发生什么情况呢?看一下下面的例子:
func('rechar', 27, 32)
运行时我们看到如下错误:
Traceback (most recent call last):
File "E:\tmp\tt.py", line 5, in <module>
func('rechar', 27, 32)
TypeError: func() takes 2 positional arguments but 3 were given
哦,python会抱怨我们传递的参数太多了。那如果确实在一些情况下,我们无法保证传递的参数数量一定和函数需要的参数数相等怎么办呢?这是就是*iterable这种参数该登场的时候了,假如在定义函数定义是,我们增加了一个参数,这个参数以一个”*“开始,那么这个参数实际上是一个tuple类型。假如传递的参数比需要的多,那那些多余的参数会被放入这个tuple中。例如,
def func(name, age, *other):
print(name, age, other)
那么,
func('rechar', 27, 32)
这个调用的输出如下:
>>> rechar 27 (32,)
四、函数定义中的”**name“
python在将所有未匹配上的非按名称匹配的参数装入参数中的tuple之后,假如还有未匹配上的按名称匹配的参数那情况会怎样呢?首先来看一下下面的示例:
def func(name, age):
print(name, age)
func(name = 'rechar', age = 27, pay='1800')
执行时,python又抱怨了:
Traceback (most recent call last):
File "E:\tmp\tt.py", line 5, in <module>
func(name = 'rechar', age = 27, pay='1800')
TypeError: func() got an unexpected keyword argument 'pay'
它说func这个函数没有名称为”pay“的参数,这种情况或许出现在我们函数重构之后,原来函数时有这个参数的。而这个函数调用可能在别处没有被修改。假设即使给了”pay“这个参数,程序的正确性不受影响,没错,这就是”**name“参数的用武之地了。
假如在函数定义中,给函数增加一个以”**“开头的参数,那么这个参数实际上是一个dict对象,它会将参数调用中所有没有被匹配的按名称传递的参数都放入这个dict中。例如,
def func(name, age,**other):
print(name, age, other)
func(name = 'rechar', age = 27, pay='1800')
那么运行结果输出,
rechar 27 {'pay': '1800'}
看到了吧,这里的other就将没有匹配的”pay=‘1800’“收入囊中了。
五、规定调用必须按名称匹配
当我们在定义函数时,如果第一个参数就是”*name“参数,那么可想而知,我们无法使用按顺序匹配的方式传递,因为所有的按顺序传递的参数值最终的归宿都会是这里的tuple当中。而为了给后续的参数传递值,我们只能使用按名称匹配的方法。
六、”**“参数只能出现在最后一个形参之后
想想为什么?其实很好理解,因为出现在”**“形参之后的形参,无论使用按顺序传递还是按名称传递,最终都无法到达参数值真正应该需要到的地方。所以python规定,如果需要”**“参数,那它必须是最后一个形参。否则python会报语法错误。
七、函数调用中的”*“
在表格中我们看到了有func(*iteratable)的调用,这个调用的意思是,iteratable必须是一个可迭代的容器,比如list、tuple;作为参数传递值,它最终传递到函数时,不是以一个整体出现,而是将其中的元素按照顺序传递的方式,一次赋值给函数的形参。例如,
li = ['rechar', 27]
func(*li)
这个函数调用与
func('rechar', 27)
是等价的。
八、函数调用中的”**“
知道”*“在函数调用中的效果之后,也就很好理解”**“的作用了。它是将传递进来的dict对象分解,每一个元素对应一个按名称传递的参数,根据其中的key对参数进行赋值。

python参数传递那些事相关推荐

  1. python参数传递方法_深入理解python中函数传递参数是值传递还是引用传递

    python 的 深入理解python中函数传递参数是值传递还是引用传递 目前网络上大部分博客的结论都是这样的: Python不允许程序员选择采用传值还是传 引用.Python参数传递采用的肯定是&q ...

  2. 经典 Python参数传递采用的肯定是“传对象引用”的方式。相当于传值和传引用的一种综合。如果函数收到的是一个可变对象(比如字典或者列表)的引用,就能修改对象的原始值--相当于通过“传引用”来传递对象

    python不允许程序员选择采用传值还是传引用.Python参数传递采用的肯定是"传对象引用"的方式.这种方式相当于传值和传引用的一种综合.如果函数收到的是一个可变对象(比如字典或 ...

  3. python 参数传递

    python 参数传递 def test1(*args):test3(*args)def test2(**kargs):test3(**kargs)def test3(a, b):print(a,b) ...

  4. python参数传递,如何让可变参数当作不可变参数传递

    引子 众所周知,python中参数传递方式有很多,这些在其他文章中都有所详细陈述,在此不做赘述.(如果你需要了解python参数传递的基本知识,请绕路,相关文章在CSDN很丰富.)但是小编遇到一个问题 ...

  5. python参数传递:对象的引用

    python参数传递:对象的引用 大家都知道在python中,一切皆对象,变量也不再具有类型,变量仅仅是对象的一个引用,我们通常用变量来测类型,通常测得就是被这个变量引用得对象的类型. 例如: 这里的 ...

  6. Python参数传递:值传递和引用传递

    前提: 1.Python 中万物皆为对象,变量以引用的方式指向对象. 2.身份 2.1 可变对象:对象的内存值可以被改变,引用变量改变后,实际上是其所指向的值发生了变化,当前这块内存区域中存放的内容发 ...

  7. python参数传递_python中的*和**参数传递机制

    python的参数传递机制具有值传递(int.float等值数据类型)和引用传递(以字典.列表等非值对象数据类型为代表)两种基本机制以及方便的关键字传递特性(直接使用函数的形参名指定实参的传递目标,如 ...

  8. python参数传递时不构造新数据对象_关于函数的参数传递(parameter passing),以下选项中描述错误的是_学小易找答案...

    [单选题]下面代码的输出结果是: a = [] for i in range(2,10): count = 0 for x in range(2,i-1): if i % x == 0: count ...

  9. python参数传递_python参数的传递

    >[danger]# 值传递和引用传递 如果你接触过其他的编程语言,比如 C/C++,很容易想到,常见的参数传递有 2 种:值传递和引用传递. >[success]1. 值传递,通常就是拷 ...

最新文章

  1. 元宇宙专题深度(附链接)
  2. c语言读取一个图像文件格式,求指导,如何用c语言实现读取*.raw格式图像
  3. c# 对象json互相转换_C#匿名对象(转JSON)互转、动态添加属性
  4. 如何在sqlserver数据库表中建立复合主键
  5. IDA分析shellcode导入windows结构体
  6. 鸿蒙系统布局,华为的布局,开始了!第二款鸿蒙系统产品,即将亮相
  7. Spring系列教程八: Spring实现事务的两种方式
  8. 匿名函数python_基于python内置函数与匿名函数详解
  9. 年度总结、下年计划不会做?教给你一个一招致胜的方法
  10. QT学习笔记(六):Qt5主窗口框架示例
  11. 九阴真经 服务器 显示维护,《九阴真经》1月29日服务器互通升级维护公告
  12. 管理感悟:怎样讲清楚自己的想法
  13. CentOS7 安装 Oracle 11g rac(7) —— 安装 grid 软件前的准备工作
  14. 木瓜移动每日快讯0511:谷歌Chrome引入新隐私功能fenced frame
  15. UML各种箭头的含义
  16. 俞伯牙摔琴谢知音的故事
  17. 1T数据到底有多大?
  18. 中国知名食品品牌策划包装设计,哪家实力最强
  19. 组队学习可汗学院统计学1
  20. 知道创宇技能表3.1

热门文章

  1. Docker 安装 openresty
  2. 农产品电商大数据 直击现代“三农”问题痛点
  3. java反射机制之数组转对象
  4. 不同设备拿到了相同的mac地址(arp和nbtstat)
  5. 服务器SqlServer2008数据库自动备份
  6. 雷蛇灵刃系列原厂预装系统自带隐藏分区还原功能
  7. electron 获取屏幕
  8. C语言/(除号)和%(取余)运算操作符讲解
  9. 于丹教授360个让人流泪的句子
  10. mybatis实现分页的几种方式