函数的定义与使用
def 函数名([参数列表]):
'''注释'''
函数体
函数参数
在Python中,函数参数有很多种:可以为普通参数、默认值参数、关键参数、可变长度参数等等。
Python在定义函数时不需要指定形参的类型,完全由调用者传递的实参类型以及Python解释器的理解和推断来决定,类似于重载和泛型。
位置参数
调用函数时实参和形参的顺序严格一致,比起实参和形参的数量必须相同
def demo(a,b,c): #所有形参都是位置参数
print(a,b,c)
>>>demo(2,3,4)
2,3,4
>>>demo(2,3,4,5) #实参与形参的数量必须相同
demo() takes 3 positional arguments but 4 were given
默认值参数
调用带有默认值参数的函数时,可以不对默认值参数进行赋值,也可以为其赋值,具有很大的灵活性。
def say(message,times = 1,sx = 2):
函数体
>>> say(1,2)
1 2 2
>>> say.__defaults__
(1, 2)
函数名.__ defaults__ 可以查看函数所有默认值参数的当前值,返回胃一个元组,元素依次表示每个默认值的当前值。
注意:默认值参数必须出现在函数参数列表的最右端,任何一个默认值参数右边不能有非默认值参数。
关键参数
关键字参数主要只调用函数时的参数传递方式,通过关键参数,实参顺序可以和形参顺序不一致,但不影响传递结果,避免了用户需要牢记位置参数顺序的麻烦。
>>> say(2,sx=3)
2 1 3
可变长度参数
可变长度参数主要有两种形式:在参数名前加1个*或2个**
*parameter用来接受多个实参并将其放在一个元组中
**parameter接受多个关键参数并存放到字典中
*parameter的用法
无论调用该函数时传递了多少实参,一律将其放入元组中
>>> def demo(*p):
print(p)
>>> demo(1,2,3)
(1, 2, 3)
>>> demo(1,2)
(1, 2)
>>> demo(1,2,3,4,5,6,7)
(1, 2, 3, 4, 5, 6, 7)
**parameter的用法
调用该函数时自动将接受的参数转换为字典
>>> def demo(**p):
for item in p.items():
print(item)
>>> demo(x=1,y=2,z=3)
('y', 2)
('x', 1)
('z', 3)
在函数定义中增加一些外围的检查代码,可以防止用户调用函数时传入无效参数。
def demo(a,b,**kwargs):
for para in kwargs.keys():
if para not in ('x','y','z')
raise Exception('{0}is not a valid parameter'.format(para))
print(a+b+sum(kwargs.values()))
# 只能接收'x','y','z',这三个参数
定义函数时可以同时使用位置参数,关键参数,默认参数和可变长度参数。一般不要这样做
降低可读性,查错困难,函数设计不好,不满足模块高内聚的要求。
强制函数的某些参数必须以关键参数形式进行传值
在函数定义是,位于*parameter活单独一个星号 *之后的所有参数都只能以关键参数的形式进行传值,不接收其他任何形式的传值。
如果需要强制所有参数都必须以关键参数形式进行传值,可以在定义函数时把单独以个星号*作为函数第一个参数。
>>> def demo(a, b, *, c):
... print(a+b+c)
...
>>> demo(1,2,c=2)
5
>>> def demo(a, b, *p, c):
... print(a+b+c+sum(p))
...
>>> demo(1,2,3,4,5,c=6)
21
传递参数是的序列解包
序列解包是非常重要且常用的一个功能。
>>> lt = [1,2,3]
>>> a, b, c = lt
>>> print(a,b,c)
1 2 3
>>> x, y, z = 1, 2, 3
>>> print(x,y,z)
1 2 3
>>> a_tuple=tuple(range(3))
>>> x,y,z = a_tuple
>>> print(x,y,z)
0 1 2
>>> x, y, z = map(str, range(3))
在Python列表、元组、集合、字典以及其他可迭代对象,对字典使用时,默认是对字典“键”进行操作,Python解释器将自动进行解包。对“键:值” 对进行操作使用字典的items()
方法,对“值”进行操作应使用 values()
方法进行指定。
>>> s = {'a':1,'b':2}
>>> a,b = s
>>> a
'a'
>>> a,b = s.items()
>>> b
('b', 2)
>>> a,b = s.values()
>>> a
1
>>> a,b,c='ABC'
>>> a
'A'
特殊用法:
>>> print(*[1,2,3],4,*(5,6))
1 2 3 4 5 6
>>> *range(3),3
(0, 1, 2, 3)
>>> {*range(3),3,4}
{0, 1, 2, 3, 4}
>>> {'a':1,**{'b':2}}
{'a': 1, 'b': 2}
序列解包逆运算
>>> a, *b, c = 1,2,3,4,5
>>> a,b,c
(1, [2, 3, 4], 5)
>>> a,*b,c=tuple(range(20))
>>> b
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18]
传递参数是的序列解包
>>> def demo(a,b,c):
... print(a,b,c)
...
>>> seq = [1,2,3]
>>> demo(*seq)
1 2 3
>>> seq = {1:'a',2:'b',3:'c'}
>>> demo(*seq)
1 2 3
>>> demo(*seq.values())
a b c
如果实参是字典 可以使用两个星号 **
进行解包,会把字典转换成类似于关键字参数的形式进行参数传递。要求实参字典中的所有键都必须是函数的形参名称,或者于函数中两个星号的可变长度参数相对应。
>>> p = {'a':1,'b':2,'c':3}
>>> def f(a,b,c=5):
... print(a,b,c)
...
>>> f(**p)
1 2 3
>>> def demo(**p):
... for item in p.items():
... print(item)
...
>>> demo(**p)
('a', 1)
('b', 2)
('c', 3)
一个函数需要以多种新式来接收参数,定义时一般把位置参数放在最前面,然后是默认值参数,接下来是一个星号的可变长度参数,最后两个星号的可变长度参数;调用函数是,一般也按照这个顺序进行参数传递。调用函数时如果对实参使用一个星号* 进行序列解包,那么这些解包后的实参将会被当做普通位置参数对待,并且会在关键参数和使用两个星号** 进行解包的参数之前进行处理。