第十八章 参数

参数传递基础

下面是给函数传递参数时的一些简要的关键点:python

  • 参数的传递是经过自动将对象赋值给局部变量名来实现的;
  • 在函数内部赋值参数名不会影响调用者;
  • 改变函数的可变对象参数的值也许会对调用者有影响;
  • 不可变参数本质上传入了‘值’;
  • 可变对象本质上传入‘指针’;

参数和共享引用

>>> def f(a):
...     a = 99
... 
>>> b = 88
>>> f(b)
>>> print(b)
88

避免修改可变参数

这里最须要记住的就是,函数可以改变传入的可变对象(例如,列表和字典),这不会是个麻烦,井且有时候这对于某些用途颇有用处。此外,原位置修改传入的可变对象的函数,多是有意面为的,例如,修改多是一个定义良好的AP的一部分,而咱们不该该经过建立复制来违反该API。
然而,你也必须意识到这个特性:若是在你没有预期的状况下外部对象发生了改变,检查一下是否是由某个被调用的函数引发的,而且有必要的话在传入对象时建立复制。web

模拟输出参数和多重结果

>>> def multiple(x, y):
...     x = 2
...     y = [3, 4]
...     return x, y
... 
>>> 
>>> X = 1
>>> L = [1, 2]
>>> X, L = multiple(X, L)
>>> X, L
(2, [3, 4])

看起来这段代码好像返国了两个值,可是实际上只有一个:一个包含2个元素的元组这里省略了它可选的圆括号,在调用返国后,咱们能使用元组赋值解包被返国元组的各部分。svg

特殊的参数匹配模型

参数匹配基础

匹配模式的大纲:函数

  • 位置次序:从左至右进行匹配
    这是通常状况,也是咱们目前为止最经常使用的方法,即经过位置进行匹配把参数值传递给函数头部的参数名称,匹配顺序为从左到右;
  • 关键字参数:经过参数名进行匹配
    此外,调用者能够经过在调用时使用参数的变量名,即便用name = value这种语法,来指定函数中的哪一个参数接受某个值;
  • 默认值参数:为没有传入值的可选参数指定参数值
    若是调用时的传入值过少的话,函数自身可以为参数指定接受的默认值,这将一样用到语法name= value;
  • 可变长参数( varanus)收集:收集任意多的基于位置成关键字的参数
    函数可以用一个星号“”或两个星号“**”开头的特殊参数,来收集任意多的额外参数。这个特性经常叫做可变长参数,借鉴自C语言中的可变长度参数列表工具,在Pyhon中,参数被收集到一个普通的对象中;
  • 可变长参数解包:传人任意多的基于位置或关键字的参数
    调用者也能使用语法去将参数集合解包成单个的参数。这个“”与在函数头部的“偏偏相反:在函数头部的“*”意味着收集任意多的参数,而在调用者中意味着解包任意多的参数并将它们做为离散的值单独传人;
  • keyword-only参数:必须按照名称传递的参数
    在 Python3.X中(不包括 Python2.X),函数也能用关键字参数来指定必须经过名称(而不是位置)来传递的参数。这样的参数一般用来定义实际使用的参数之外的配置选项;
语法 位置 解释
func(value) 调用者 常规参数:经过位置匹配
func(name=value) 调用者 关键字参数:经过名称匹配
func(*iterable) 调用者 将 iterable中全部的对象做为独立的基于位置的参数传入
func(**dict) 调用者 将dct中全部的键/值对做为独立的关键字参数传入
def func(name) 函数 常规参数:经过位置或名称匹配
def func( name=value) 函数 默认值参数值,若是没有在调用时传入的话
def func(*name) 函数 数将剩下的基于位置的参数匹配井收集到一个元组中
def func(**name) 函数 将剩下的关键字参数匹配并收集到一个字典中
def func(* other,name) 函数 在调用中必须经过关键字传入的参数(仅限3X)
def func(*, name=value) 函数 在调用中必须经过关键字传入的参数(仅限3X)

更深刻的细节

函数参数应遵循下面这些顺序规则:工具

  • 在函数调用时,参数必须按此顺序出现:
    全部基于位置的参数(value);
    全部关键字参数(name=value);
    *iterable形式的组合;
    **dict;
  • 在函数头部,函数必须按此顺序出现:
    全部一把参数(name);
    全部默认值参数(name=value);
    *name形式;
    name=value的keyword-only参数,以后是**name形式;

python内部大体是使用如下的步骤来在赋值前匹配参数的:spa

  1. 经过位置分配无关键字参数;
  2. 经过匹配名称分配关键字参数;
  3. 将剩下的关键字参数分配到**name元组中;
  4. 把默认值分配给在头部未获得匹配的参数;

关键字参数和默认值参数的示例

>>> def f(a, b, c): print(a, b, c)
... 
>>> f(1, 2, 3)
1 2 3

这里,咱们基于位置传入值:a匹配到1,b匹配到2,c匹配到3;指针

关键字参数

关键字参数容许咱们经过名称匹配,而不是基于位置。仍是同一个函数code

>>> f(c=3, b=2, a=1)
1 2 3

默认值参数

简而言之,默认值参数容许咱们让特定的参数变为可选的。若是没有传入值的话,在函数运行前参数就会被赋予默认值。例如,下面是这个函数须要一个参数,另外两个参数默认:xml

>>> def f(a, b=2, c=3): print(a, b, c)
... 
>>> f(1)
1 2 3
>>> f(1, 4)
1 4 3
>>> f(1, c=6)
1 2 6

混合使用关键字参数和默认值参数

下面这段代码中,调用者必须老是传入至少两个参数(匹配spam和eggs),不过另外两个是可选的:对象

def func(spam, eggs, toast=0, ham=0):
	print(spam, eggs, toast, ham)

func(1, 2)						# output:(1, 2, 0, 0)
func(1, ham=1, eggs=0)			# output:(1, 0, 0, 1)
func(spam=1, eggs=0)			# output:(1, 0, 0, 0)
func(toast=1, eggs=2, spam=3)	# output:(3, 2, 1, 0)
func(1, 2, 3, 4)				# output:(1, 2, 3, 4)

可变长参数的实例

‘*’和‘**’做为最后两种匹配的扩展,旨在让函数支持接受任意多的参数。

函数定义中:收集参数

其中第一种用法,是在函数定义中把不能匹配的基于位置的参数收集到一个元组:

>>> def f(*args):
...     print(args)
... 
>>> f(1, 2, 3, 4)
(1, 2, 3, 4)

‘**’的特性与之相似,可是它只对关键字参数有效。他将这些关键字参数收集到一个新的字典中,这个字典以后将可以用通常的字典工具处理

>>> def f(**args):print(args)
... 
>>> f(a=1, b=2)
{'a': 1, 'b': 2}

函数调用中:解包参数

基于位置的解包参数:

>>> def func(a, b, c, d):print(a, b, c, d)
... 
>>> args = (1, 2, 3, 4)
>>> func(*args)
1 2 3 4

基于关键字的解包参数:

>>> def func(a, b, c, d):print(a, b, c, d)
... 
>>> args = {'a': 1, 'b':s 2, 'c': 3, 'd':4}
>>> 
>>> func(**args)
1 2 3 4

一样,能够调用时可以以很是灵活的方式混用通常参数、基于位置的参数以及关键参数:

>>> func(*(1, 2), **{'d': 4, 'c': 3})
1 2 3 4
>>> func(1, *(2, 3), **{'d': 4})
1 2 3 4
>>> func(1, c=3, *(2,), **{'d': 4})
1 2 3 4
>>> func(1, *(2, 3), d=4)
1 2 3 4
>>> func(1, *(2,), c=3, **{'d': 4})
1 2 3 4