Python的函数定义非常简单,但灵活度却非常大。除了正常定义的必选参数外,还可以使用默认参数、可变参数和关键字参数,使得函数定义出来的接口,不但能处理复杂的参数,还可以简化调用者的代码。
位置参数
例如:
def power(x): return x * x ```
对于power(x)函数,参数x就是一个位置参数。
当我们调用power函数时,必须传入有且仅有的一个参数x:
```python >>> power(5) 25 >>> power(15) 225
|
默认参数
def power(x, n=2): s = 1 while n > 0: n = n - 1 s = s * x return s
|
可以在定义函数时,默认给上一个参数 n=2
使用默认参数能够最大的好处是能降低调用函数的难度。
默认参数很有用,但使用不当,也会掉坑里。默认参数有个最大的坑,演示如下:
def add_end(L=[]): L.append("END") return L
print(add_end([1,2,3])) print(add_end(['x','y','z'])) print(add_end()) print(add_end()) print(add_end())
|
会输出
[1, 2, 3, 'END'] ['x', 'y', 'z', 'END'] ['END'] ['END', 'END'] ['END', 'END', 'END']
|
我们可以看到,第一次和第二次输出都没有问题,因为我们传了参数进去,第三次我们输入,会返回默认的 ‘END’,但是第四次和第五次就有问题了。
原因解释如下:
Python函数在定义的时候,默认参数L的值就被计算出来了,即[],因为默认参数L也是一个变量,它指向对象[],每次调用该函数,如果改变了L的内容,则下次调用时,默认参数的内容就变了,不再是函数定义时的[]了。
我们要修改下该函数
def add_end(L=None): if L is None: L =[] L.append("END") return L
|
定义默认参数要牢记一点:默认参数必须指向不变对象!
为什么要设计str、None这样的不变对象呢?因为不变对象一旦创建,对象内部的数据就不能修改,这样就减少了由于修改数据导致的错误。此外,由于对象不变,多任务环境下同时读取对象不需要加锁,同时读一点问题都没有。我们在编写程序时,如果可以设计一个不变对象,那就尽量设计成不变对象。
可变参数
在Python函数中,还可以定义可变参数。顾名思义,可变参数就是传入的参数个数是可变的,可以是1个、2个到任意个,还可以是0个。
要定义出这个函数,我们必须确定输入的参数。由于参数个数不确定,我们首先想到可以把a,b,c……作为一个list或tuple传进来,这样,函数可以定义如下:
def calc(num): sum = 0 for n in num: sum = sum +n * n return sum
|
但是调用的时候,需要先组装出一个list或tuple:
print(calc([1,2,3]))
print(calc([1,3,5,7]))
|
改为可变参数.
def calc(*num): sum = 0 for n in num: sum = sum +n * n return sum
print(calc(1,2,3))
|
定义可变参数和定义一个list或tuple参数相比,仅仅在参数前面加了一个*号。在函数内部,参数numbers接收到的是一个tuple,因此,函数代码完全不变。但是,调用该函数时,可以传入任意个参数,包括0个参数
那如果要传入一个 list 或 tuple 呢
def calc(*num): sum = 0 for n in num: sum = sum +n * n return sum
nums = [1,2,3]
print(calc(*nums))
|
*nums表示把nums这个list的所有元素作为可变参数传进去。这种写法相当有用,而且很常见。
关键字参数
def person(name,age,**kw): print('name:',name,'age:',age,'other:',kw) person('Michael',30) person('Michael',30,city='Beijing')
```
输出
```python name: Michael age: 30 other: {} name: Michael age: 30 other: {'city': 'Beijing'} ```
关键字参数有什么用?它可以扩展函数的功能。比如,在person函数里,我们保证能接收到name和age这两个参数,但是,如果调用者愿意提供更多的参数,我们也能收到。试想你正在做一个用户注册的功能,除了用户名和年龄是必填项外,其他都是可选项,利用关键字参数来定义这个函数就能满足注册的需求。
传入一个字典
```python extra = {'city':'Beijing','Job':'Engineer'} person('zhangsan',30,**extra) ```
对于关键字参数,函数的调用者可以传入任意不受限制的关键字参数。至于到底传入了哪些,就需要在函数内部通过kw检查。
如需限制传入参数: ```python def person(name,age,*,city,job): print(name,age,city,job)
person('zhangsan',30,city='hangzhou',job='Techs')
|
和关键字参数**kw不同,命名关键字参数需要一个特殊分隔符*,*后面的参数被视为命名关键字参数。
def person(name,age,*,city='beijing',job): print(name,age,city,job) person('zhangsan',30,job='Techs') ```
|
在Python中定义函数,可以用必选参数、默认参数、可变参数、关键字参数和命名关键字参数,这5种参数都可以组合使用。但是请注意,参数定义的顺序必须是:必选参数、默认参数、可变参数、命名关键字参数和关键字参数。
```python
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) print(f1(1,2)) print(f1(1,2,c=3)) print(f1(1,2,3,'a','b')) print(f1(1,2,3,'a','b','c',d=11))
|
输出
a= 1 b= 2 c= 0 args= () kw= {} None a= 1 b= 2 c= 3 args= () kw= {} None a= 1 b= 2 c= 3 args= ('a', 'b') kw= {} None a= 1 b= 2 c= 3 args= ('a', 'b', 'c') kw= {'d': 11} None
|
传入tuple 和 dict
args = (1,2,3,4,5)
kw = {'d':99,'x':44}
print(f1(*args,**kw))
*args是可变参数,args接收的是一个tuple;
**kw是关键字参数,kw接收的是一个dict。
学习笔记来自廖雪峰的 python
文章作者:阿文
版权声明:本博客所有文章除特别声明外,均采用
CC BY-NC-SA 4.0 许可协议。转载请注明来自
阿文的博客!