函数的参数是参数暴露给外部的接口, 向函数传递参数, 可以控制函数的流程, 函数可以 0 个, 1 个或多个参数; 在 Python 中向函数传参, 使用的是赋值方式.
一, 传递参数
参数是通过赋值来传递的, 传递参数的特点是:
参数的传递是通过自动把对象赋值给函数的本地变量名来实现的,
在函数内部的变量名的赋值不会影响调用者, 在函数运行时, 在函数头部的参数名是一个新的, 本地的变量名, 这个变量名的作用域是在函数的本地作用域内.
改变函数的可变对象参数的值, 会修改原始对象的值.
当通过赋值方式, 把可变对象的引用传递给函数时, 在函数内部对参数进行修改, 在函数外部可以看到修改.
例如, 列表是一个可变对象, 当把列表 a 传递给 changer 函数时, 函数向列表末尾添加一个字符 a, 当函数调用结束时, 列表末尾被修改.
- >>> def changer(x):
- ... x.append('a')
- ...
- >>> a=[1,2,3]
- >>> changer(a)
- >>> a
- [1, 2, 3, 'a']
这是由于可变对象是通过指针进行传递的, 当把列表的引用传递给参数时, 函数直接在原处修改对象.
也可以通过向参数传递拷贝的方式, 使得函数无法修改原始的对象.
- changer(a[:])
- changer(a.copy())
二, 参数匹配模型
不管使用何种参数的匹配模型, 参数总是通过赋值进行传递的.
在默认情况下, 参数是通过其位置进行匹配的, 从左向右, 而且必须精确地传递和函数头部参数名一样多的参数. 还能够通过参数名匹配, 默认参数名, 以及对于额外参数的容器来进行传参.
1, 位置匹配
一般情况下, 参数是通过位置从左至右进行匹配, 把参数传递给函数头部的参数名称.
例如, 定义函数 func, 包含三个参数, 那么必须使用三个参数传值进行调用:
def func(a,b,c):
调用的格式是, 按照顺序把值写在括号中, Python 按照位置匹配参数, 把 1 赋值给 a, 把 2 赋值给 b, 把 3 赋值给 c:
func(1,2,3)
2, 关键字匹配
调用者使用 arg_name=value 的方式, 通过在调用时使用参数的变量名进行匹配.
例如, 定义参数 func, 包含三个参数, 那么必须使用三个参数传值进行调用:
def func(x,y,z):
使用关键字调用的格式是: 按照 arg=named 的方式进行匹配, 可以不按照位置:
func(y=2, x=1, z=3)
在调用函数时, Python 按照参数名进行匹配, 把 2 传递给参数 y, 把 1 传递给参数 x, 把 3 传递给参数 z.
也可以混合使用位置匹配和关键字匹配, 例如, 下面的函数调用:
func(1,z=3,y=2)
基于位置的匹配参数, 首先按照从左至右的顺序匹配前面的参数, 之后, 再按照基于变量名进行关键字匹配.
3, 默认参数
在定义函数时, 可以为函数的参数赋值, 这就是参数的默认值. 当没有为该参数传值时, 参数值使用默认值.
例如, 定义一个函数, 包含三个参数, x,y 和 z, 其中参数 z 有默认值 1:
def func(x,y,z=1):
当调用这个函数, 必须为参数 x 和 y 传值, 无论是通过位置匹配还是关键字匹配来实现都可以. 然而, 参数 z 的传值是可选的. 如果不为 z 传值, 那么 z 使用默认值; 如果为 z 传值, 那么 z 使用传递的值.
func(2,3)
4, 可变长参数列表
可变参数用于收集任意多个基于位置或关键字的参数, 在函数定义时, 如果参数名前带一个 * 号, 那么该参数收集的是基于位置的传值; 如果参数名前带两个 * 号 (**arg), 那么该参数收集的是基于关键字(arg=value) 的传值.
- def func(*args)
- def func(**dict)
这两种方式的不同点是,*args 方式是把任意多个传值封装成元组(arg1,arg2), 而 **dict 是把任意多个 arg=value 封装成字典{arg:value}, 字典的 key 是参数名, 字典 key 对应的值是参数的值.
例如, 定义函数 foo, 包含一个位置匹配参数, 1 个可变的位置匹配参数, 1 个可变的关键字匹配参数:
def foo(a,*b,**c):
在调用函数时, 首先按照位置匹配, 把 1 传递给参数 a, 把元组 (2,3) 传递给参数 b, 把字典 {x:1,y:2} 传递给参数 c:
foo(1,2,3,x=1,y=2)
5, 只能使用关键字参数
参数必须按照名称传值, 在函数定义时, 参数必须在调用中按照关键字进行传值:
def func(*,arg=value)
从语法上来讲, keyword-only 参数编码为关键字参数, 出现在参数列表的 * args 之后, 所有这些参数都必须在调用中使用关键字语法来传值.
def foo(a,*b,c):
在调用 foo 函数时, 参数 a 可以按照位置和关键字来传值, 参数 b 接收按照其余的按照位置来传值的变量, 参数 c 必须按照关键字来传值:
foo(1,2,'a',3,c='key')
也可以在参数列表中使用一个 * 字符, 来表示一个函数不会接受一个可变的参数列表, 而是仍然期待跟在 * 后面的所有参数都作为关键字匹配.
例如, 定义函数 foo, 只接受 3 个参数, 不接受可变长度的参数列表:
def foo(a,*,b,c):
在调用时, 参数 a 可以按照位置和关键字来传值, 参数 b 和 c 必须按照关键字来传值:
foo(1,b='x',c=2)
三, lambda 表达式
除了 def 语句之外, Python 还提供了一种生成函数对象的表达式形式, lambda 表达式. 就像 def 语句一样, 这个表达式创建了一个函数对象, 但是它返回了一个函数, 而不是把这个函数赋值给一个变量名.
lambda 表达式的一般形式是关键字 lambda, 之后是一个或多个参数(与一个 def 头部内用括号括起来的参数列表极其类似), 紧跟一个冒号, 之后是一个表达式:
lambda arg1,arg2,... argN: expression_using_args
lambda 表达式的特性是:
lambda 表达式返回的是函数对象;
lambda 是一个表达式, 而不是一个语句, 作为一个表达式, lambda 返回了一个值(一个新的函数), 可以选择性地赋值给一个变量名;
lambda 的主体是一个单个的表达式, 而不是一个代码块, 这个表达式的结果作为函数的结果返回.
lambda 只有一行表达式, 只能用于创建简单的函数, 而 def 可以包含多条语句, 用于处理复杂的任务.
对于简单的处理流程, 既可以使用 def, 也可以用 lambda 来实现, 例如:
- def func(x,y,z): return x+y+z
- func=lambda x,y,z: x+y+z
由于 lambda 表达式返回的是一个函数对象, 因此, 可以用于 map(),filter()和 reduce()函数中:
- list(map((lambda x: x+3), range(0,5)))
- list(filter((lambda x: x>2), range(0,5)))
- from functools import reduce
- reduce((lambda x,y: x+y),range(0,5))
reduce()函数对每对元素都应用函数, 并运行到最后结果, 上述 reduce()函数的作用是把序列中的所有元素相加, 等价的写法是:
- x=list(range(0,5)]
- res=x[0]
- for i in x[1:] :
- res+=i
四, 函数的属性
可以向函数添加任意多个用户定义的属性, 函数属性的格式是: 函数名称. 变量名
例如, 向函数 func 中添加 state 属性:
- def func():
- func.state='begin'
参考文档:
来源: https://www.cnblogs.com/ljhdo/p/10127541.html