函数是最小的基本功能单元,能够增强代码的可读性,易于管理,而且Python作为支持函数式编程的语言,广泛的使用必不用说。
虽说Python函数的定义非常简单,但是却非常灵活,特别是函数参数的使用,使得函数定义出来的接口能够处理复杂的参数问题,简化调用者的代码。Python中函数的参数类型有:必选参数、默认参数、可变参数、关键字参数、命名关键字参数等
默认参数
>>> def cal_power(x, n):
s = 1
while n > 0:
s = s * x
n = n - 1
return s
>>> cal_power(5,3)
125
上面这个函数计算x的n次方,非常简便。但是按照使用情况来看,如果大多情况计算的是二次方,那么每一次都需要输入参数2,能不能简便一些只输入一个参数呢?下面这样就可以了嘛!
>>> def cal_power(x, n = 2):
s = 1
while n > 0:
s = s * x
n = n - 1
return s
>>> cal_power(5)
25
>>> cal_power(5, 3)
125
默认参数能够在保证强大功能的前提下,简化使用者的调用。
默认参数的使用需要注意:
- 默认参数一定要放在必选参数后面;
- 默认参数必须指向不变对象!
如果有多个默认参数,在调用的时候一般需要按照顺序传入参数;同时,并非一定要将所有的可选参数全都传入,可以使用参数名只传入某一个参数。
>>> def cal_power(x, n = 2, add = 5):
s = 1
while n > 0:
s = s * x
n = n - 1
return s + add
>>> cal_power(5, 3, 10)
135
>>> cal_power(5, 3)
130
>>> cal_power(5, add = 10)
35
随心所欲!就是这么任性
可变参数
>>> def cal_add(numbers):
s = 0
for i in numbers:
s = s + i
return s
>>> list = [2,4,6,8]
>>> tuple = (2,4,6,8)
>>> cal_add(list)
20
>>> cal_add(tuple)
20
上面的这样一个函数,允许传入一个可iterable的且包含数字的对象,并对其中所有的元素进行相加。
但是每一次都构造一个可遍历对象,很不方便。如果能够利用可变参数,就可以将可变数量的参数传入函数,实施计算。
>>> def cal_add(*numbers):
s = 0
for i in numbers:
s = s + i
return s
>>> cal_add(2,4,6,8)
20
>>> cal_add(2,4,6)
12
>>> cal_add()
0
只需要将参数前面加上*
就可以构造一个可变参数。而实际上,在函数内部调用时,numbers接收到的是一个由传入参数构成的tuple,所以代码保持不变。但是调用函数却时可以传入任意个参数!
但是如果现在已经有一个list或者tuple,需要传入参数,逐一传入当然是可行的,但很麻烦,可以直接在list或tuple前加一个*
,将其中的元素作为可变参数传入!
>>> cal_add(*list)
20
>>> cal_add(*tuple)
20
*nums表示把nums这个list的所有元素作为可变参数传进去。这种写法相当有用,而且很常见!
关键字参数
可变参数允许你传入任意个参数,调用时自动组装成tuple;而关键字参数允许你传入任意个含参数名的参数,这些关键字参数在调用时自动组装成为一个dict
>>> def person(name,age,**kw):
print('name:',name,'age',age,'other',kw)
>>> person("MrHammer",24,city='Nanjing',hometown='Jiangxi')
name: MrHammer age 24 other {'city': 'Nanjing', 'hometown': 'Jiangxi'}
关键字参数能够扩展函数的功能,用于接收一些可选功能!
和可选参数类似,也可以先组织一个dict对象,再使用**dict传入关键字参数,而调用时函数内部将参数重新组织成为一个dict。
>>> myInfo = {'city': 'Nanjing', 'hometown': 'Jiangxi'}
>>> person("MrHammer",24,**myInfo)
name: MrHammer age 24 other {'city': 'Nanjing', 'hometown': 'Jiangxi'}
>>>
命名关键字参数
如果想要限制传入参数的关键字名称,可以使用以下方法进行限制。
>>> def person(name,age,*,city,hometown):
print('name:',name,'age',age,'other',city, hometown)
>>> person("MrHammer",24,city='Nanjing',hometown='Jiangxi')
name: MrHammer age 24 other Nanjing Jiangxi
使用一个*
作为特殊分隔符,*
之后的参数就被作为命名关键字参数,命名关键字参数是必填参数,没法缺省,而且只能输入相应名字的参数。但同时输出的结果就不是dict对象,而直接是相应的值了。
>>> person("MrHammer",24,city='Nanjing',hometown='Jiangxi',sex='male')
Traceback (most recent call last):
File "<pyshell#79>", line 1, in <module>
person("MrHammer",24,city='Nanjing',hometown='Jiangxi',sex='male')
TypeError: person() got an unexpected keyword argument 'sex'
上面的问题说明:命名关键字说明之外的参数是没法被接收的!
>>> person("MrHammer",24,'Nanjing','Jiangxi')
Traceback (most recent call last):
File "<pyshell#80>", line 1, in <module>
person("MrHammer",24,'Nanjing','Jiangxi')
TypeError: person() takes 2 positional arguments but 4 were given
上面的问题说明:虽说关键字的名称已经指定了,但仍旧需要以键值对的方式传入参数!否则会被默认为位置参数!
如若参数中已经含有一个可变参数了,就不需要用’*’,可变参数后面跟着的就是命名关键字参数!
>>> def person(name,age,*args,city,hometown):
print('name:',name,'age',age,'other',args,city, hometown)
>>> person('Mr',24,14,58,3.20,city='Nanjing',hometown='fad')
name: Mr age 24 other (14, 58, 3.2) Nanjing fad
参数组合
在Python中,必选参数、默认参数、可变参数、关键字参数、命名关键字参数可以互相组合使用,参数定义的顺序一定是必选参数、默认参数、可变参数、命名关键字参数、关键字参数,顺序一定不能乱!前面的是单个的参数,而后面是键值对参数。
>>> def person(name,age,*args,city='Nanjing',hometown,**kw):
print(name,age,args,city,hometown,kw)
>>> person('MrHammer',24,*(50,'shade of gray',51),hometown='Jx')
MrHammer 24 (50, 'shade of gray', 51) Nanjing Jx {}
>>> person('MrHammer',24,*(50,'shade of gray',51),hometown='Jx',sex='male',hobby='jogging')
MrHammer 24 (50, 'shade of gray', 51) Nanjing Jx {'hobby': 'jogging', 'sex': 'male'}
你看,多么完美,将所有参数都用上了,命名关键字参数之后还可以接任意个关键字参数。
那么,最神奇的是下面的用法
>>> args = ('MrHammer',24,50,'shade of gray',51)
>>> kw = {'hometown':'Jx','sex':'male','hobby':'jogging'}
>>> person(*args,**kw)
MrHammer 24 (50, 'shade of gray', 51) Nanjing Jx {'hobby': 'jogging', 'sex': 'male'}
看到了吗!也就是我们常说的,任何函数都能够用fun(*args,**kw)
的形式来调用,无论是怎么定义的!
(By MrHammer 2016-05-18 下午2点 @Hohai Clody)