函数的参数
定义函数的时候,我们把参数的名字和位置确定下来,函数的接口定义就完成了。
python的函数除了正常的定义必选参数外,还可以使用默认参数,可变参数合关键字参数,
位置参数
定义一个计算x 的平方的函数
1
2
3
4
5
6
|
>>>
def
power(x):
#参数 x 就是一个位置参数
return
x
*
*
2
>>> power(
5
)
25
>>> power(
15
)
225
|
为了方便我们再定义一个可以计算 x 的任意次的函数
1
2
3
4
5
6
|
>>>
def
powern(x,n):
return
x
*
*
n
>>> powern(
5
,
2
)
25
>>> powern(
2
,
3
)
8
|
这是powern中的 x,n 都是位置参数,按 x和n 的位置对应的传入参数
默认参数
对于powern(x,n)如果只穿入一个参数
1
2
3
4
5
|
>>> powern(
5
)
Traceback (most recent call last):
File
"<pyshell#10>"
, line
1
,
in
<module>
powern(
5
)
TypeError: powern() missing
1
required positional argument:
'n'
|
python会抛出错误提示少一个参数
这时我们可以 设置 默认参数:
1
2
3
4
5
6
|
>>>
def
powern(x,n
=
2
):
#在这里把n=2 设置位默认参数
return
x
*
*
n
>>> powern(
5
)
25
>>> powern(
5
,
3
)
125
|
当只输入一个参数x 时相当于 计算 x 的平方
设置默认函数可以简化函数的调用。设置默认参数时,有有几点需要注意:
1:必选参数在前,默认参数在后。
2:如何设置默认参数。当函数有多个参数时,把变化大的参数放在前面,变化小的参数放在后面。变化小的参数就可以设置为默认参数。
默认参数很有用,但使用不当会掉坑,默认参数有个最大的坑,比如:
先定义一个函数,传入一个list ,添加一个 END 再返回:
1
2
3
|
>>>
def
add_end(L
=
[]):
L.append(
'END'
)
return
L
|
调用时,结果似乎不错:
1
2
3
4
|
>>> add_end([
1
,
2
,
3
])
[
1
,
2
,
3
,
'END'
]
>>> add_end([
'x'
,
'y'
,
'z'
])
[
'x'
,
'y'
,
'z'
,
'END'
]
|
使用默认参数是,一开始结果也不错:
1
2
|
>>> add_end()
[
'END'
]
|
但是,再次调用add_end()时,结果就不对了:
1
2
3
4
|
>>> add_end()
[
'END'
,
'END'
]
>>> add_end()
[
'END'
,
'END'
,
'END'
]
|
函数似乎“记住了”上次添加了‘end’的list
为什么呢:
python在定义的时候,默认参数L的值就被计算出来,即[ ] ,因为默认参数L也是一个变量,它指向对象
[ ] ,如果改变了L的内容,则下次调用时,默认参数的内容就变了,不在是定义的 [ ] 了。
所以,定义默认参数要牢记一点:默认参数必须指向不变的对象。!!
要修改上面的例子,我们可以用 None 这个 不变对象来实现:
1
2
3
4
5
|
>>>
def
add_end(L
=
None
):
if
L
is
None
:
L
=
[]
L.append(
'END'
)
return
L
|
这用我们在调用就不会出错了:
1
2
3
4
|
>>> add_end()
[
'END'
]
>>> add_end()
[
'END'
]
|
在做一下对比:
1
2
3
4
5
6
7
8
9
10
|
>>>
def
add_end(L
=
[]):
if
L
is
None
:
L
=
[]
L.append(
'END'
)
return
L
>>> add_end()
[
'END'
]
>>> add_end()
[
'END'
,
'END'
]
|
可变参数
可变参数就是传入参数的个数是可变的,可以是任意个。
比如:给定一组数字a,b,c........,计算 a2 + b2+ c2 + ……。
要定义出这个函数,我们必须确定输入的参数。由于参数个数是不确定的,我们首先想到可以吧a,b,c,.......。作为一个list或tuple 传进去,这样函数可定义为:
1
2
3
4
5
|
>>>
def
calc(number):
sum
=
0
for
n
in
number:
sum
=
sum
+
n
*
*
2
return
sum
|
但是在调用的时候,需要先组装出一个list或tuple:
1
2
3
4
|
>>> calc([
1
,
2
,
3
])
14
>>> calc([
1
,
2
,
3
,
4
])
30
|
如果利用可变参数,调用函数的方式可以简化:
1
2
3
4
|
>>> calc(
1
,
2
,
3
)
14
>>> calc(
0
)
0
|
所以我们需要把函数改变为可变参数:
1
2
3
4
5
|
>>>
def
calc(
*
number):
sum
=
0
for
n
in
number:
sum
=
sum
+
n
*
*
2
return
sum
|
定义可变参数和定义一个list或tuple参数相比,仅仅在参数前面加了一个*号。在函数的内部,参数 number 接受到的是一个tuple,因此,函数代码完全不变。但是,调用该函数时,可以传入任意个参数,包括0个参数。
1
2
|
>>> calc()
0
|
如果已经有一个list或者tuple,要调用一个可变参数怎么办?可以这样做:
1
2
3
|
>>> nums
=
[
1
,
2
,
3
]
>>> calc(nums[
0
],nums[
1
],nums[
2
])
14
|
这种方法太繁琐,所以 python 允许在list或tuple的元素前面加一个*号,把list或tuple的元素变成可变参数传进去:
1
2
|
>>> calc(
*
nums)
14
|
*num表示把num这个list的所有元素作为可变参数穿进去。这种写法相当有用,而且很常见。
关键字参数
可变参数允许你传入0或任意个参数,这些可变参数在函数调用时自动组装为一个tuple。而关键字参数允许你传入0个参数或任意个含参数名的参数,这些关键字参数在函数内部自动组装为一个dict。
1
2
|
>>>
def
person(name,age,
*
*
kw):
print
(
'name:'
,name,
'age:'
,age,
'other:'
,kw)
|
函数person除了必选参数 name 和 age 外,还接受关键字参数 kw 。在调用该函数是,可以之传入必选参数:
1
2
3
4
5
6
|
>>> person(
'Michael'
,
30
)
name: Michael age:
30
other: {}
>>> person(
'Bob'
,
35
,city
=
'BeiJing'
)
name: Bob age:
35
other: {
'city'
:
'BeiJing'
}
>>> person(
'xiaoming'
,
19
,gender
=
'M'
,job
=
'Enginerr'
)
name: xiaoming age:
19
other: {
'gender'
:
'M'
,
'job'
:
'Enginerr'
}
|
关键字参数有什么用?它可以扩展函数的功能。比如,在person
函数里,我们保证能接收到name
和age
这两个参数,但是,如果调用者愿意提供更多的参数,我们也能收到。试想你正在做一个用户注册的功能,除了用户名和年龄是必填项外,其他都是可选项,利用关键字参数来定义这个函数就能满足注册的需求。
和可变关键字类似,也可以先组装出一个dict,然后,吧该dict转换为关键字参数传进去:
1
2
3
|
>>> exter
=
{
'city'
:
'BeiJing'
,
'Job'
:
'Engineer'
}
>>> person(
'Jack'
,
24
,city
=
exter[
'city'
],job
=
exter[
'Job'
])
name: Jack age:
24
other: {
'job'
:
'Engineer'
,
'city'
:
'BeiJing'
}
|
当然,上面复杂的调用可以用简化的写法:
1
2
|
>>> person(
'Jack'
,
24
,
*
*
exter)
name: Jack age:
24
other: {
'Job'
:
'Engineer'
,
'city'
:
'BeiJing'
}
|
**extra
表示把extra
这个dict的所有key-value用关键字参数传入到函数的**kw
参数,kw
将获得一个dict,注意kw
获得的dict是extra
的一份拷贝,对kw
的改动不会影响到函数外的extra
。
命名字关键字参数
对于关键字参数,函数的调用者可以传入任意不受限制的关键字参数。至于到底传入了哪些,就需要在函数内部用过 kw 检查
1
2
3
4
5
6
|
>>>
def
person(name,age,
*
*
kw):
if
'city'
in
kw:
#city有参数
pass
if
'job'
in
kw:
#有job参数
pass
print
(
'name:'
,name,
'age'
,age,
'other:'
,kw)
|
但是任可以传入不受限制的关键字参数:
1
2
|
>>> person(
'jack'
,
24
,city
=
'beijing'
,addr
=
'chaoyang'
,zipcode
=
123456
)
name: jack age
24
other: {
'zipcode'
:
123456
,
'addr'
:
'chaoyang'
,
'city'
:
'beijing'
}
|
如果要限制关键字参数的名字,就可以用命名关键字参数,例如,只接收city
和job
作为关键字参数。这种方式定义的函数如下:
1
2
|
>>>
def
person(name,age,
*
,city,job):
print
(name,age,city,job)
|
和关键字参数**kw不同,命名关键字参数需要一个特殊分隔符*,*后面的参数被视为命名关键字参数。
1
2
|
>>> person(
'jack'
,
24
,city
=
'beijing'
,job
=
'engineer'
)
jack
24
beijing engineer
|
命名关键字参数传入参数名,这和位置参数不同。如果没有传入参数名,调用将报错:
1
2
3
4
5
|
>>> person(
'jack'
,
24
,
'beijing'
,
'engineer'
)
Traceback (most recent call last):
File
"<pyshell#85>"
, line
1
,
in
<module>
person(
'jack'
,
24
,
'beijing'
,
'engineer'
)
TypeError: person() takes
2
positional arguments but
4
were given
|
由于调用时缺少参数名city
和job
,Python解释器把这4个参数均视为位置参数,但person()
函数仅接受2个位置参数。
命名关键字参数可以有缺省值,从而简化调用:
1
2
|
>>>
def
person(name,age,
*
,city
=
'BeiJing'
,job):
print
(name,age,city,job)
|
由于命名关键字参数city
具有默认值,调用时,可不传入city
参数:
1
2
|
>>> person(
'Jack'
,
24
,job
=
'Engineer'
)
Jack
24
BeiJing Engineer
|
使用命名关键字参数时,要特别注意,*
不是参数,而是特殊分隔符。如果缺少*
,Python解释器将无法识别位置参数和命名关键字参数:
1
2
3
|
>>>
def
person(name,age,city,job):
#缺少 *, city 和job 被视为位置参数
pass
|
参数组合
在Python中定义函数,可以用必选参数、默认参数、可变参数、关键字参数和命名关键字参数,这5种参数都可以组合使用,除了可变参数无法和命名关键字参数混合。但是请注意,参数定义的顺序必须是:必选参数、默认参数、可变参数/命名关键字参数和关键字参数。
比如定义一个函数,包含上述若干种参数:
1
2
3
4
5
6
|
def
f1(a, b, c
=
0
,
*
args,
*
*
kw):
print
(
'a ='
, a,
'b ='
, b,
'c ='
, c,
'args ='
, args,
'kw ='
, kw)
def
f2(a, b, c
=
0
,
*
, d,
*
*
kw):
print
(
'a ='
, a,
'b ='
, b,
'c ='
, c,
'd ='
, d,
'kw ='
, kw)
|
在函数调用的时候,Python解释器自动按照参数位置和参数名把对应的参数传进去。
1
2
3
4
5
6
7
8
9
10
|
>>> f1(
1
,
2
)
a
=
1
b
=
2
c
=
0
args
=
() kw
=
{}
>>> f1(
1
,
2
, c
=
3
)
a
=
1
b
=
2
c
=
3
args
=
() kw
=
{}
>>> f1(
1
,
2
,
3
,
'a'
,
'b'
)
a
=
1
b
=
2
c
=
3
args
=
(
'a'
,
'b'
) kw
=
{}
>>> f1(
1
,
2
,
3
,
'a'
,
'b'
, x
=
99
)
a
=
1
b
=
2
c
=
3
args
=
(
'a'
,
'b'
) kw
=
{
'x'
:
99
}
>>> f2(
1
,
2
, d
=
99
, ext
=
None
)
a
=
1
b
=
2
c
=
0
d
=
99
kw
=
{
'ext'
:
None
}
|
最神奇的是通过一个tuple和dict,你也可以调用上述函数:
1
2
3
4
5
6
7
8
|
>>> args
=
(
1
,
2
,
3
,
4
)
>>> kw
=
{
'd'
:
99
,
'x'
:
'#'
}
>>> f1(
*
args,
*
*
kw)
a
=
1
b
=
2
c
=
3
args
=
(
4
,) kw
=
{
'd'
:
99
,
'x'
:
'#'
}
>>> args
=
(
1
,
2
,
3
)
>>> kw
=
{
'd'
:
88
,
'x'
:
'#'
}
>>> f2(
*
args,
*
*
kw)
a
=
1
b
=
2
c
=
3
d
=
88
kw
=
{
'x'
:
'#'
}
|
所以,对于任意函数,都可以通过类似func(*args, **kw)
的形式调用它,无论它的参数是如何定义的。
本文转自 nw01f 51CTO博客,原文链接:http://blog.51cto.com/dearch/1760470,如需转载请自行联系原作者