python可变参数调用函数问题

一直使用python实现一些想法,最近在使用python的过程中出现这样一个需求,定义了一个函数,第一个是普通参数,第二个是默认参数,后面还有可变参数,在最初学习python的时候,都知道非关键字可变参数和关键字可变参数两种,调用的方式也非常多种多样,这里主要提出一个比较隐含的问题,并将各种可能出现的情况进行了探讨。

函数声明格式

python虽然不支持函数重载,但是通过对函数参数的众多特性的支持基本弥补了。函数声明的通式如下:

def func(argv1,argv2...[,argv_d = default1,...]        [,*var_argv][,**var_key_argv])

这是python函数声明的通式,首先是普通参数若干个,也可以没有,接着是带默认值的参数,然后是非关键字可变参数,最后是关键字可变参数。这为python提供的强大函数调用奠定了基础。

函数调用

正是在函数调用的过程中遇到了问题。为了说明,我定义了一个如下的函数进行说明:

def f1(a,b=1,*var): print a,‘\t‘,b,‘\t‘,var
def f2(a,b=1,**var): print a,‘\t‘,v,‘\t‘,var

首先普通参数可以使用按位置的方式调用,同时可以使用按形参关键字调用。默认值参数也是使用位置方式匹配或者关键字调用。实例如下:

这里没有使用后面的可变参数,一切都没有问题。问题是,本人遇到的一个需求是,默认参数需要就是使用默认值调用,同时还有可变参数,而且是非关键字参数,那么调用时就会出现下面的情况:

可以看到,通过非关键字可变参数传入参数之后,python会默认把非关键字可变参数的前面若干个(这里是1个)当做默认参数,这里是因为我没有提供默认参数b的值,正是这个原因,在我的程序中一直没发现。后来自习思考一下,发现Python解释器做出这样的决定还是有一定的道理的,因为非关键字可变参数是默认参数之后的若干个参数,而在调用的时候由于没有传入默认参数的值,Python无法判断到底从哪里开始是可变参数,因此在没有传入默认参数的值时,就依次从非关键字参数(调用者认为的)中按照顺序抽取去当做默认参数的值,这从侧面论证了非关键字可变参数在python内部是和普通参数默认参数一并处理的

虽然上述调用有些极端,但是确实会出现这样的需求,那么可以使用关键字可变参数进行替换,上述问题就可以解决了,因为解释器是可以区别关键字参数和默认参数的,调用如下:

在使用关键字可变参数时,还有一个重要问题就是,关键字参数的键值不能有普通参数或者默认参数的参数名重复,这从侧面论证了,python对关键字调用和关键字可变参数在内部都是经过同一个字典保存的,因此不能有重复的键,调用如下:

上述遇到的问题是在实际操作过程中遇到的,一般从各种教程、书本学习python都只是说明上述的函数声明和调用的方式,但是几乎没有这种实际操作中可能遇到的点点滴滴,因此学习任何东西最好的方式就动手,这个真理永远不会变啦!

时间: 2024-10-04 15:18:10

python可变参数调用函数问题的相关文章

Objective-C可变参数的函数实现

1.前言 相信接触过OC的对NSLog都很熟悉,细心查看NSLog的原始定义,会发现,他的原型如下: FOUNDATION_EXPORT void NSLog(NSString *format, ...) NS_FORMAT_FUNCTION(1,2); 路径在:OS X version/Frameworks/Foundation/NSObjCRuntime.h 注意到参数最后的...,这里是可变参数.这样,在调用时就可以根据需要传入相应个数的参数了. PS:其实在C#中也有params指定可变

C语言利用va_list、va_start、va_end、va_arg宏定义可变参数的函数

在定义可变参数的函数之前,先来理解一下函数参数的传递原理: 1.函数参数是以栈这种数据结构来存取的,在函数参数列表中,从右至左依次入栈. 2.参数的内存存放格式:参数的内存地址存放在内存的堆栈段中,在执行函数的时候,从最后一个(最右边)参数开始入栈.因此栈底高地址,栈顶低地址,举个例子说明一下: void test(int a, float b, char c); 那么,在调用test函数的时候,实参char c先进栈,然后是float b,最后才是int a,因此在内存中变量的存放次序是c->

可变参数的函数与宏

1.可变参数的函数 <stdarg.h>头文件中定义了一些宏,用于可变参数的函数,如下 va_list:这种类型声明局部状态变量,假设变量名为va(用于下面的描述),用于遍历函数. va_start:这个宏初始化状态变量va,要先调用之后才能调用va_arg与va_end. va_arg:这个宏返回参数表中下一个参数的值,将内部指针(在va中)移到下一个参数,下一个参数的类型要用type指定,使va_arg能够计算其在堆栈中的长度,调用va_start之后第一次调用va_arg返回第一个可变参

C语言中可变参数的函数(三个点,“...”)

C语言中可变参数的函数(三个点,"...") 本文主要介绍va_start和va_end的使用及原理. 在以前的一篇帖子Format MessageBox 详解中曾使用到va_start和va_end这两个宏,但对它们也只是泛泛的了解. 介绍这两个宏之前先看一下C中传递函数的参数时的用法和原理: 1.在C中,当我们无法列出传递函数的所有实参的类型和数目时,可以用省略号指定参数表 void foo(...); void foo(parm_list,...); 这种方式和我们以前认识的不大

可变参数的函数(variadic function)的陷阱

1,介绍variadic function 可变参数的函数就是参数数量可以改变的函数.例如printf(): int printf(const char *format, ...); printf("%d%s\n",i,s); C语言之所以可以支持可变参数函数,一个重要的原因是C调用规范中规定C语言函数调用时,参数是从右向左压入栈的:这样一个函数实现的时候,就无需关心调用他的函数会传递几个参数过来,而只要关心自己用到几个:例子: #include<stdarg.h> voi

可变参数列表函数实现

如题 我们在写可变参数列表函数之前,先来了解一下什么是可变参数列表函数. 我们在c语言编程中有时会遇到 一些参数个数可变的函数,例如printf()函数,其函数原型为: int printf(const char* format,-): 它除了有一个参数format固定以外,后面跟的参数个数和类型是可变的(用三个点"..."做参数占位符),实际调用时可以有以下的形式: printf("%d",i); printf("%s",s); printf(

Python可变参数函数用法详解

来自:http://c.biancheng.net/view/2257.html 很多编程语言都允许定义个数可变的参数,这样可以在调用函数时传入任意多个参数.Python 当然也不例外,Python 允许在形参前面添加一个星号(*),这样就意味着该参数可接收多个参数值,多个参数值被当成元组传入. 下面程序定义了一个形参个数可变的函数: # 定义了支持参数收集的函数 def test(a, *books) : print(books) # books被当成元组处理 for b in books :

Python 可变参数

定义可变参数 如果想让一个函数能接受任意个参数,我们就可以定义一个可变参数: def fn(*args): print args #coding=gbk def kebian(*arg): return arg print(kebian(1)) print(kebian('Str')) print(kebian([1,2,3])) print(kebian({'right':1,'left':2})) 可变参数的名字前面有个 * 号,我们可以传入0个.1个或多个参数给可变参数: >>>

Python可变参数*和**

可变参数 在Python函数中,还可以定义可变参数.顾名思义,可变参数就是传入的参数个数是可变的,可以是1个.2个到任意个,还可以是0个. 我们以数学题为例子,给定一组数字a,b,c--,请计算a2 + b2 + c2 + --. 要定义出这个函数,我们必须确定输入的参数.由于参数个数不确定,我们首先想到可以把a,b,c--作为一个list或tuple传进来,这样,函数可以定义如下: def calc(numbers): sum = 0 for n in numbers: sum = sum +