定义函数时,我们确定了参数的名称和位置,对于调用者而言,无需知道函数内部的逻辑,只需要知道怎样正确的传入参数即可。别人编写的函数,你只要知道怎么用就好了。
除了正常定义的必选参数外,还可以使用默认参数、可变参数和关键字参数,使得函数定义出来的接口,不但能处理复杂的参数,还可以简化调用者的代码。
什么叫位置参数
>>> def p(x): return x*x >>> p(2) 4 >>> p(5) 25
如上,我们定义了一个计算平方的函数p(x),x就是它的位置参数,那如果要定做x的三次方、四次方、五次方呢?不能每个都给定义个函数,于是我们需要修改只有一个参数的p(x)为传入两个参数的p(x,n),如下:
>>> def p(x,n): return x**n >>> p(2,10) 1024 >>> p(2,-10) 0.0009765625
新的函数p(x,n)有两个位置参数,调用函数时,传入的两个值,分别按顺序给x,n赋值
默认参数
算个平方都要输两个数,太麻烦了,可不可以算平方的时候只用传入一个参数x呢?可以的!我们对函数做一下改写,换一种计算方式:
>>> def p(x,n=2): s=1 while n>0: n=n-1 s=s*x return s >>> p(10) 100 >>> p(10,2) 100
这里用了一个循环算法,并给n一个默认值2,这样p(10)和p(10,2)其实是一样的,现在p(x)这个函数对于计算平方的数据传入就只需传入一个数值,方便调用者使用。
注意事项:
1、默认参数要放到必选参数后面,因为我们知道,函数调用时,是按位置顺序传入,如果定义时把默认参数放在前,函数会把传入的第一个数值赋值给设定好的默认参数,从而会产生错误。
2、有多个参数时,变化的可能性大的参数放前面,变化的可能性小的参数放后面可作为默认参数。
从上面的两个例子可以看出,使用默认参数配置函数,最大的好处就是调用时可以简化数据的传入,例如我们要统计某小学一年级学生信息,包括姓名、性别、年龄、城市,对于同一年级学生而言年龄和城市大多数都是相同的,我们就可以使用默认参数:
>>> def tongji(姓名,性别,年龄=6,城市='北京'): print('姓名:',姓名) print('性别:',性别) print('年龄:',年龄) print('城市:',城市) >>> tongji('张三','男') 姓名: 张三 性别: 男 年龄: 6 城市: 北京 >>> tongji('李四','女','7') 姓名: 李四 性别: 女 年龄: 7 城市: 北京 >>> tongji('王五','男',城市='天津') 姓名: 王五 性别: 男 年龄: 6 城市: 天津
如上,我们给tongji()这个函数设定了两个默认参数,张三同学6岁,来自北京,所以后两项可以不录入;李四7岁,来自北京,传入的参数可以在姓名性别后追加一个年龄的参数;王五年龄是6岁符合默认参数,但是城市是天津,我们要跳过年龄的默认参数就必须直接写明城市=’天津’替换城市的默认参数。
注意:默认参数必须指向不可变对象,如下面例子,定义一个新的函数,传入list,在list结尾加一个END:
>>> def add_end(L=[]): L.append('END') return L >>> add_end([1,2,3]) [1, 2, 3, 'END'] >>> add_end(['A','B','C']) ['A', 'B', 'C', 'END'] >>> add_end() ['END'] >>> add_end() ['END', 'END'] >>> add_end() ['END', 'END', 'END']
前三次调用运行都没问题,当多次使用默认参数调用时,结果却变了,每调用一次,就多增加一个END。这是因为定义函数时,变量L就指向了空[]这个list,而这个list是个变量,调用一次函数,这个对象就发生一次变化从空[]变成了END,第二次调用,L指向的对象由END变成了END,END。
上面这个例子我们修改如下:
>>> def add_end(L=None): if L is None: L=[] L.append('END') return L >>> add_end() ['END'] >>> add_end() ['END']