给函数传递不定个数的参数

转载:http://blog.csdn.net/u012102306/article/details/52250028 收藏参考

问题起源

在Python中常常看到有这样的函数,它们的入口参数的个数是不定的。比如有如下代码

In: print zip([1, 2],[3, 4])
Out: [(1, 3), (2, 4)]
In: print zip([1, 2],[3, 4],[5, 6])
Out: [(1, 3, 5), (2, 4, 6)]

其中zip是Python自带的一个函数,其作用么,相信聪明的你已经看出来了。那如果有一天我们也要写一个能接受任意输入个数的python函数,该如何实现呢?

今天我就遇到这个问题,然后花了一点时间解决了——答案是,借助*这个符号。虽然这是个很基础的问题,网上资料很多,但还是想自己总结一下。

从求和函数谈起

我们不妨先定义一个灰常简单的函数——实现两个整数相加

def add_2_int(a1, a2):
    return a1+a2

一目了然,这就好比刚学编程时的print "hello world!"

不满足于此的我们,总想搞个大新闻——比如

实现多个整数的相加,但,事先不知道有几个整数。

这时我们就需要再学习一个——借助万能的*,来改写原函数:

def add_int(*a):
    s = 0
    for e in a:
        s += e    return s

我们先不管函数是怎么定义的、*a是什么含义,我们先看下怎么调用这个函数

In: print add_int(1, 2)
Out: 3 In: print add_int(1, 2, 3)
Out: 6

无论输入几个整数,都能求和,可见,这个函数已经能实现我们想要的功能了。

回过头看,这里调用add_int时输入参数是三个:1,2,3,但给add_int定义的输入是*a,那*的作用到底是什么呢?其实就是在调用函数时,把输入的三个参数1,2,3打包成一个元组(tuple),即打包成(1,2,3)a这个参数,为了证明这点,我们不妨在函数中间加一个print语句

def add_int(*a):
    s = 0
    print "input a is: ", a    for e in a:
        s += e    return s

调用函数并看下输出:

In: print add_int(1, 2, 3)
Out: input a is:  (1, 2, 3)     6

确实若我们所料。

这时我们脑洞开始变大了,如果我输入不是三个1,2,3,而是本身是一个列表[1,2,3],会不会也能实现求和呢?比如有如下代码

a_list = [1, 2, 3]print add_int(a_list)

啊哦,报错了:unsupported operand type(s) for +=: ‘int‘ and ‘list‘,说list不能跟int相加。我们分析一下,按照刚刚的理论,这里调用add_int时,只给了一个参数a_list,于是*a会将a_list打包成(a_list, )a,当我们执行for e in a语句时,得到的是a里面的每个元素,也就是a_list,而不是a_list里面的元素,所以显然无法得到想要的结果。

实现列表的连接

既然上面报错了,那我们索性将错就错,设计一个函数

实现任意多个list的『相加』——对于list而言+就是连接

我们只需修改函数add_int中用于存放累加结果的变量s即可,即:

def add_list(*a):
    s = [] # 因为要返回list,所以s的初始值是[]而不是0
    for e in a:
        s += e    return s

比如我们要连接三个list[1,2],[3,4],[5,6],只需调用add_list([1, 2],[3, 4],[5, 6])即可得到[1, 2, 3, 4, 5, 6]

系铃和解铃

注意,上面我们说来说去,都是在函数定义阶段使用*来打包(系铃),使得函数能接受任意多的入口参数个数。现在遇到一个新问题:

给定两个整数求和函数(即上面的add_2_int(a1, a2)),现在有一个元组a_tuple = (1, 2),求1+2

暂时忘却刚说到的*,为了解决这个问题,一般我们会逐个取出a_tuple里的1,2,然后再调用函数,比如add_2_int(a_tuple[0], a_tuple[1])。有没有更简洁的方法呢?比如我们能否用某种手段使得输入的a_tuple自动拆开(解铃)成两个参数1, 2再输入函数呢?

答案是肯定的——还是用*,写成add_2_int(*a_tuple),注意,现在是函数调用阶段,这里*的作用跟定义函数时恰恰相反,是将a_tuple(1,2)拆开成1, 2两个参数输入函数,对应函数的两个入口参数a1, a2 (扩展一下,这种函数的参数传递方式在Python中叫按位置传递,还有按关键字传递的方法,本文就不细说了)

解更多的铃

其实上面这个问题的想法来源很朴素——既然*可以在函数定义时把入口参数『打包』成tuple类型,那我在函数调用时,也可以将tuple类型的变量『解压』成一个一个的入口参数。那么问题就来了,延续上述问题,我把问题变成:

给定add_2_int(a1, a2),现在有一个列表a_list = [3, 4],一个集合a_set = set([6, 5]),求  3+4 5+6

不怕不怕,我们发现在解铃阶段(即函数调用阶段),  *不光能拆开tuple类型,包括set,list等通通可以,也就是通通可以这样调用函数: add_2_int(*a_list),add_2_int(*a_set)

如果你脑洞再打开一点,之前我们用*定义了add_int(*a)函数,现在有a_list=[1,2,3],那么我们调用add_int(*a_list)会产生什么效果呢?

总结一下

本文简单实验了一下*在python函数中的作用,主要是区分函数定义和函数调用两个阶段,我把它称作系铃和解铃。

如果本文能对你编写python函数有所帮助,也不枉鄙人熬夜啦善莫大焉~

原文地址:https://www.cnblogs.com/xiaoxiao-niao/p/8215236.html

时间: 2024-10-01 02:09:34

给函数传递不定个数的参数的相关文章

给函数传递不定关键字的参数 和

转载:http://blog.csdn.net/u012102306/article/details/52250050 收藏一下 在上一篇文章『[Python]给函数传递不定个数的参数』中,我们主要讲解了*在函数定义和函数调用阶段的不同作用,并留了一个小问题: 我们用*定义了add_int(*a)函数,现在有a_list=[1,2,3],那么我们调用add_int(*a_list)会产生什么效果呢? 如果文章你已看懂,那不难知道,最后被传到函数当中的a是(1,2,3),因为经历了先用*解压--把

Object... 不定个数的参数列表

Object是所有类的基类,这个你可以查询jdk文档了解,所有类都继承自Object.Object ...objects这种参数定义是在不确定方法参数的情况下的一种多态表现形式.即这个方法可以传递多个参数,这个参数的个数是不确定的.这样你在方法体中需要相应的做些处理.因为Object是基类,所以使用Object ...objects这样的参数形式,允许一切继承自Object的对象作为参数.这种方法在实际中应该还是比较少用的. Object[] obj这样的形式,就是一个Object数组构成的参数

Javascript事件函数传递的event对象参数

Event属性和方法: 1. type:事件的类型,如onlick中的click: 2. srcElement/target:事件源,就是发生事件的元素: 3. button:声明被按下的鼠标键,整数,1代表左键,2代表右键,4代表中键,如果按下多个键,酒把这些值加起来,所以3就代表左右键同时按下:(firefox中 0代表左键,1代表中间键,2代表右键) 4. clientX/clientY:事件发生的时候,鼠标相对于浏览器窗口可视文档区域的左上角的位置:(在DOM标准中,这两个属性值都不考虑

PHP函数(二)-不定参数的传递

如果要传递不定数量的参数,需要使用func_get_args()函数来传递 func_num_args()函数用来返回参数的总数 <?php function more_args(){ $args = func_get_args(); for($i=0;$i<func_num_args();$i++){ $a = $i +1; echo "第".$a."个参数是".$args[$i]."<br>"; } } more_ar

判断函数传递的参数个数

看zepto源码时,看到了很多基于1 in arguments和0 in arguments的判断. 基本了解是在判断函数调用时,是否传递了需要的参数, 但真心不明白这个0和1究竟是啥. 经高人指点,其实应当是arguments类数组的下标. i当做arguments的属性,输出. 当判断1的时候,表示如果存在至少两个参数,才会输出1,否则不会输出任何内容. 即0和1或者更大的数字,是类数组的arguments的下标.

scala 学习笔记(03) 参数缺省值、不定个数参数、类的属性(Property)

继续学习,这一篇主要是通过scala来吐槽java的,同样是jvm上的语言,差距咋就这么大呢? 作为一个有.NET开发经验的程序员,当初刚接触java时,相信很多人对java语言有以下不爽(只列了极小一部分): 1. 一堆的setter/getter方法,没有c#中的property属性概念 2. 方法的参数值,不能设置缺省值 3. 不定个数参数的写法太单一 ... 然后java的拥护者讲出一堆大道理,说这样设计是如何如何有道理,各种洗脑,时间长了,也就被迫习惯了.要不是遇到scala,我还真就

Javascript参数个数可变的函数 动态传人和取得参数

js中的函数是一个对象,一个Function对象(函数参数列表及函数主体事实上只是Function对象的构造函数的参数而已),跟其他对象一 样可以在运行时增加属性.删除属性,函数参数是可变的,比如定义函数时定义的参数列表只有3个参数,调用时你却可以只传2个参数,或超过3个参数,通过函 数对象的length属性可以得到函数定义的形参个数,而函数调用时的实际参数列表则可以通过函数的arguments属性(一个Arguments对 象,类似于数组)访问到,arguments.length就是实际参数的

C语言结构体及函数传递数组参数示例

注:makeSphere()函数返回Sphere结构体,main函数中,调用makeSphere()函数,传递的第一个参数为数组,传递的数组作为指针. 版权声明:本文为博主原创文章,未经博主允许不得转载.

js中函数传递参数,究竟是值传递还是引用传递?

记住真理: js函数传递参数,不管是简单数据类型,还是引用数据类型,都是值传递!! 下面是js红包书里面的例子: function setName(obj) { obj.name = "Nicholas"; obj = new Object(); obj.name = "Greg"; } var person = new Object(); setName(person); alert(person.name); // "Nicholas" 肯定