def SumFun(*args):
result = 0
for x in args[0:]:
result +=x
return result
print( SumFun(2,4))
6
print (SumFun(1,2,3,4,5))
15
print (SumFun())
0
def category_table (**kwargs) :
for name ,value in kwargs.items ():
print ('{0} is a kind of {1}'.format(name, value))
category_table (apple = "fruit", carrot = 'vegetable',Python = 'programming language')
category_table(BMW = 'Car')
apple is a kind of fruit carrot is a kind of vegetable Python is a kind of programming language BMW is a kind of Car
如果一个函数中同时定义了普通参数、默认参数,以及上述两种形式的可变参数,那么 使用情况又是怎样的呢?来看一个简单的问题。
def setaxis(x,y, xlabel="x", ylabel="y",*args, **kwargs):
print(x,y,xlabel, ylabel, args, kwargs)
# pass
对于上面的函数下面几种调用方式哪些是不正确的呢?
setaxis (2,3, "testl", "test2nr","test3", my_kwarg="test3")
setaxis (2,3, "testl", my_kwarg="tGst3H" )
setaxis ("testl","test2 ", xlabel="new_x", ylabel = "new_y", my_kwarg="test3f")
setaxis (2,'test2f',fylabel = 'new_y',my_kwarg="test3M")
2 3 testl test2nr ('test3',) {'my_kwarg': 'test3'} 2 3 testl y () {'my_kwarg': 'tGst3H'} testl test2 new_x new_y () {'my_kwarg': 'test3f'} 2 test2f x y () {'fylabel': 'new_y', 'my_kwarg': 'test3M'}
答案是:上面的所有调用方式都是合法的!实际上在4种不同形式的参数同时存在的情况下.
会首先满足普通参数1然后是默认参数,如果剩余的参数个数能够掩盖所有的默认参数,
则默认参数会使用传递时候的值,如函数在调用的时候xlabel和ylabd的值分别为“test1”和“test2”;
如果剩余参数个数不够,则尽最大可能满足默认参数的值,xkbel值为而 ylabd
则使用默认参数y。
除此之外其余的参数除了键值对以外所有的参数都将作为 args
的可变参数,kwargs
则与键值对对应。
为什么慎用可变长度参数
那么,为什么要慎用可变长度参数呢?原因如下:
使用过于灵活。上面的示例
set_axis()
随随便便就能写出好几种不同形式的调用方式。 在混合普通参数或者默认参数的情况下,变长参数意味着这个函数的签名不够清晰,存在多种调用方式。 如果调用者需要花费过多的时间来研究该方法如何调用,显然这并不是一种值得提倡的方式,即使它很炫, 很高端大气上档次,但在团队合作开发的项目中,千万不要有这种想法,团队开发不是个人竞技场, 代码编写从某种程度上说也是一种沟通,清晰准确是一个很重要的指标。另外变长参数可能会破坏程序的健壮性。如果一个函数的参数列表很长,虽然可以通过使用
argS
和Mkwargs
来简化函数的定义, 但通常这意味着这个函数可以有更好的实现方式,应该被重构。前面的例子中SumFun(*args)
如果改为def Sum(seq)
, 在调用之前将需要传递的参数保存在一个序列中,如seq = (l,2,3,4,5,6J)
, 再将序列seq
作为参数传入Sum
中也是一个不错的选择。 同样如果使用-kwargs
的目的仅仅是为了传入一个字典,这将是一个非常糟糕的选择。
可变长参数适用情况
可变长参数适合在下列情况下使用(不仅限于以下场景):
为函数添加一个装饰器。
def mydecorator (fun):
def new(*args,**kwarge):
return fun(*args,**kwarge)
return new
如果参数的数目不确定,可以考虑使用变长参数。
如配置文件 test.xfg
内容如下:
(Defaults]
name = test
version = 1.0
platform = windows
fun(**kcwargs)
用于读取一些配罝文件中的值并进行全局变量初始化。
from ConfigParser import ConiigParser
conf = ConfigParser()
conf.read('test.cfg')
ccmf_dict = diet(conf.items(•Defaults r))
def func(* *kwargs):
kwargs.update <c〇nf_dict)
global name
name =kwargs.get(* name *)
global version
version = kwargs.get ('version r)
global platform
platform = Jcwargs .get ( platform*)
用来实现函数的多态或者在继承情况下子类需要调用父类的某些方法的时候。
class A(object):
def somefun(self,pl,p2):
pass
class B(A):
def myfun (self,*arg,**kwargs):
super(B,self) .somefun(*args,**kwargs)