局部命名空间为各个参数值创建了一个名字,一旦函数开始执行,就能访问这个名字了。
在函数调用时,有非关键字参数和关键字参数之分,非关键字参数必须位于关键字参数之前。
在函数定义时,严格的顺序是:位置参数,默认参数,可变长元组,可变长字典。
一:调用函数时的参数
a:关键字参数
关键字参数的概念仅仅针对函数的调用。这种理念是让调用者通过函数调用中的参数名字来区分参数。这样规范允许参数不按顺序,因为解释器能通过给出的关键字来匹配参数的值。
假设有一个函数叫做net_conn(),需要两个参数host 和port:
def net_conn(host, port): net_conn_suite
只要按照函数声明中参数定义的顺序,输入恰当的参数,自然就可以调用这个函数:net_conn('kappa',8080)
host 参数得到字符串'kappa', port 参数得到整数8080。
也可以不按照函数声明中的参数顺序输入,但是要输入相应的参数名,如下例:net_conn(port=8080, host='chino')
b:参数组
Python允许通过一个把元组、列表(非关键字参数)或字典(关键字参数)作为参数组传递给函数。也就是说,可以将所有参数放进一个元组或者字典中,仅仅用这些装有参数的容器来调用一个函数,而不必显式地将它们放在函数调用中:func(*tuple_grp_nonkw_args, **dict_grp_kw_args)
其中的tuple_grp_nonkw_args是以元组或列表形式体现的非关键字参数组,dict_grp_kw_args 是装有关键字参数的字典。实际上,也可以给出形参!这些参数包括标准的位置参数和关键字参数,所以在python中允许的函数调用的完整语法为:
func(positional_args, keyword_args, *tuple_grp_nonkw_args, **dict_grp_kw_args)
比如:
def fun(a, b, c, d, e, f, g): print 'a is', a print 'b is', b print 'c is', c print 'd is', d print 'e is', e print 'f is', f print 'g is', g alist = [1,3,4] adict = {'d':5, 'e':6, 'f':7, 'g':8}
fun(*alist, **adict)结果是:
a is 1 b is 3 c is 4 d is 5 e is 6 f is 7 g is 8
二:声明函数时的参数
a:位置参数
位置参数就是我们熟悉的标准化参数。位置参数必须以在被调用函数中定义的准确顺序来传递。比如:
def foo(who): print ‘Hello,’, who
这里foo函数就有一个位置参数。所以,调用foo时,必须有唯一的一个参数,不能多也不能少。
无论何时调用函数,都必须提供函数的所有位置参数。可以不按顺序地将关键字参数传入函数。所以,上例可以这样调用:
foo('world') foo(who = 'hehe')
b:默认参数
默认参数就是声明了默认值的参数。因为给参数赋予了默认值,所以, 在函数调用时,可以不向该参数传入值。
注意:在函数定义时,所有的位置参数必须出现在任何一个默认参数之前。否则的话,解释器将不知道如何匹配参数。例子如下:
def net_conn(host, port=80, stype='tcp'): print 'host is ', host print 'port is ', port print 'stype is ', stype net_conn('phaze', 8080, 'udp') net_conn('kappa') net_conn('chino', stype='icmp') net_conn(stype='udp', host='solo') net_conn('deli', 8080) net_conn(port=81, host='chino')
注意:在函数调用时,非关键字参数必须在关键字参数之前,所以,如果最后一个例子为:net_conn(port=81,'chino')的话,就会报语法错误:SyntaxError: non-keyword arg after keyword arg
在Python中,函数还可以处理可变数量的参数。变长的参数,称之为非正式参数。它们在函数声明中不是显式命名的,因为参数的数目在运行时之前是未知的。
Python 有两种支持变长参数的方法,在函数调用中,可以使用*和**符号来指定元组和字典的元素作为非关键字以及关键字参数。在函数定义中,将再次使用相同的符号,表示可变参数。
c:非关键字可变长参数
当函数被调用的时候,所有的位置参数和默认参数被赋值之后,剩下的非关键字参数就会按顺序插入到一个元组中。
这种机制类似于C语言中的“varargs“语法。在Python中迭代所有的元组元素和在C中用va_arg 是相同的。
可变长的参数元组必须在位置和默认参数之后,带元组(或者非关键字可变长参数)的函数普遍的语法如下:
def function_name([formal_args,] *vargs_tuple): "function_documentation_string" function_body_suite
星号操作符之后的形参将作为元组传递给函数,元组保存了所有传递给函数的"额外"的参数(匹配了所有位置和具名参数后剩余的)。如果没有给出额外的参数,元组为空。
如果没有可变参数,则只要在函数调用时给出不正确的函数参数数目,就会产生一个TypeError异常。通过末尾增加一个可变的参数列表变量,我们就能处理当超出数目的参数被传入函数的情形,因为所有的额外(非关键字)参数会被添加到变量参数元组。
例子如下:
def tupleVarArgs(arg1, arg2='defaultB', *theRest): print 'formal arg1:', arg1 print 'formal arg2:', arg2 for eachXtrArg in theRest: print 'another arg:', eachXtrArg >>>tupleVarArgs('abc') formal arg 1: abc formal arg 2: defaultB >>> >>>tupleVarArgs(23, 4.56) formal arg 1: 23 formal arg 2: 4.56 >>> >>>tupleVarArgs('abc', 123, 'xyz',456.789) formal arg 1: abc formal arg 2: 123 another arg: xyz another arg: 456.789
d:关键字可变长参数
如果有不定数目的或者额外的关键字参数,则剩余的关键字参数被放入一个字典中,字典中键为参数名,值为相应的参数值。
使用字典作为可变长关键字参数来应对额外关键字参数的函数定义的语法如下:
def function_name([formal_args,] [*vargst,] **vargsd): function_documentation_string function_body_suite
例子:
def dictVarArgs(arg1, arg2='defaultB', **theRest): print 'formal arg1:', arg1 print 'formal arg2:', arg2 for eachXtrArg in theRest.keys(): print 'Xtra arg %s: %s' % (eachXtrArg, str(theRest[eachXtrArg])) >>>dictVarArgs(1220, 740.0, c='grail') formal arg1: 1220 formal arg2: 740.0 Xtra arg c: grail >>> >>>dictVarArgs(arg2='tales', c=123, d='poe', arg1='mystery') formal arg1: mystery formal arg2: tales Xtra arg c: 123 Xtra arg d: poe >>> >>>dictVarArgs('one', d=10, e='zoo', men=('freud', 'gaudi')) formal arg1: one formal arg2: defaultB Xtra arg men: ('freud', 'gaudi') Xtra arg d: 10 Xtra arg e: zoo
下面是更多调用带有可变长参数的例子,注意,在调用时,如果混用关键字参数和非关键字参数,则先匹配位置参数,关键字参数只能处理位置参数之后的参数。比如:
def fun(a, b, c): pass fun(100, c = 1, a = 2)
会发生语法错误:TypeError: fun() got multiple values for keyword argument 'a'
def newfoo(arg1, arg2, *nkw, **kw): print 'arg1 is:', arg1 print 'arg2 is:', arg2 for eachNKW in nkw: print 'additional non-keyword arg:', eachNKW for eachKW in kw.keys(): print "additional keyword arg '%s': %s" %(eachKW, kw[eachKW]) >>>newfoo('wolf', 3, 'projects', freud=90, gamble=96) arg1 is: wolf arg2 is: 3 additional non-keyword arg: projects additional keyword arg 'freud': 90 additional keyword arg 'gamble': 96 >>>newfoo(10, 20, 30, 40, foo=50, bar=60) arg1 is: 10 arg2 is: 20 additional non-keyword arg: 30 additional non-keyword arg: 40 additional keyword arg 'foo': 50 additional keyword arg 'bar': 60
下面,将非关键字参数放在元组中,将关键字参数放在字典中:
>>>newfoo(2, 4, *(6, 8), **{'foo': 10, 'bar': 12}) arg1 is: 2 arg2 is: 4 additional non-keyword arg: 6 additional non-keyword arg: 8 additional keyword arg 'foo': 10 additional keyword arg 'bar': 12 >>>aTuple = (6, 7, 8) >>>aDict = {'z': 9} >>>newfoo(1, 2, 3, x=4, y=5, *aTuple, **aDict) arg1 is: 1 arg2 is: 2 additional non-keyword arg: 3 additional non-keyword arg: 6 additional non-keyword arg: 7 additional non-keyword arg: 8 additional keyword arg 'y': 5 additional keyword arg 'x': 4 additional keyword arg 'z': 9
注意我们的元组和字典参数仅仅是被调函数中最终接收的元组和字典的子集。额外的非关键字值‘3’以及关键字‘x’和‘y'对也被包含在最终的参数列表中。