Python的函数参数和递归参数
位置参数
def power(x):
return x*x;
默认参数
指的是在函数定义的时候,就赋予一些参数默认值,在调用这个函数的时候不必多次传入重复的参数值。
如定义一个多次输出同一个年龄阶段和同一个城市的学生的姓名和性别。
def info(name,gender,age=20,city='sichuan'):
print('name:', name)
print('gender:', gender)
print('age',age)
print('city',city)
info("xiaoqian","nv")
info("xiangj",'nan')
从上面可以看出,默认参数可以简化函数的调用,设置默认参数时,有几点要注意:
一是必选参数在前,默认参数在后。
二是如何设置默认参数。
但是默认参数虽然好,但是也有坑:就是在定义默认参数的时候,默认参数必须是不可变对象。
可变参数(*)
可变参数就是传入的参数个数是可变的,可以是1个,2个或多个,甚至是0个
def calc(*numbers):
sum = 0;
for n in numbers:
sum = sum + n;
return sum;
calc();
calc(1,2,3);
如果有一个list或者是tuple,要调用一个可变参数怎么办?
python允许在list或者tuple前面加上*,传给函数。
num = [1,2,3];
cal(*num);
可变参数允许传入0,1,n个参数,在调用的时候会自动将这些参数组装成一个tuple。而关键字参数允许你传入0个或人一个含参数名的参数,这些关键字参数在函数内部自动组装成一个dict。
关键字参数(**)
def person(name,age,**kw):
print('name',name,'age',age,'other',kw)
person('tom',20);
person('tom1',10,city="beijinh");
person('tom2',30,gender="m",city="beijing");
也可以将上面的gender和city参数组装成一个dict后,再传给函数
extra = {'city':'beijing','job':'engin'};
person('tom11',100,city=extra['city'],job=extra['job']);
person("tom11",100,**extra);
//注意这里kw获得的是extra的一份拷贝,对kw的改动不会影响到函数外的extra
命名关键字参数(*特殊分隔符)
关键字参数的调用,函数可以接受不受限制的关键字参数。
但是有时候也需要限制关键字参数个数,所以这时候就需要用到命名关键字参数
def person(name,age,*,city,job):
print(name,age,city,job);
//命名关键字参数需要一个特殊分隔符*,*后面的参数被视为命名关键字参数。
person("jackl",14,city="beijing",job="gee");
//命名关键字参数必须传入参数名,这和位置参数不同,如果没有传入参数名,调用就将报错
如果函数定义中已经有了一个可变参数,后面跟着的命名关键字参数就不需要*这个特殊分隔符了。
def person(name,age,*args,city,job):
print(name,age,args,city,job)
要特别注意:如果没有可变参数,必须加一个作为特殊分隔符,否则Python将无法识别位置参数和命名关键字参数。
总结:
python函数一共有5种参数:必选参数,默认参数,可变参数,关键字参数,命名关键字参数。可以将这几个参数组合使用。但是要注意:参数定义的顺序必须是:
必选参数,默认参数,可变参数,命名关键字参数和关键字参数。
默认参数一定要用不可变对象
args是可变参数,args接受的是一个tuple。
**kw是关键字参数,kw接受的是一个dict。
可变参数可以直接传入:func(1,2,3),又可以组装list或者tuple,再通过args传入:func((1,2,3))
关键字参数既可以直接传入func(a=1,b=2),又可以先组装dict,然后通过kw传入func()
命名关键字参数是为了限制调用者可以传入的参数名,同时可以提供默认值。
定义命名的关键字出纳号苏时,在没有可变参数的情况下,不要忘了写特殊分隔符*,否则定义的将是位置参数。
递归函数
递归函数的优点是定义简单,逻辑清晰。但是有时候会出现栈溢出。
解决栈溢出的方法是尾递归。事实上,尾递归和循环的效果是一样的,把循环看成一种特殊的尾递归函数也是可以的
尾递归:在函数返回的时候,调用自身本身,并且,return语句不能包含表达式。
def fact(n):
if n == 1:
return 1
return n * fact(n-1)
上面的return中包含了表达式,这种不是尾递归。
def fact_item(num,product):
if num == 1:
return product
return fact_item(num-1,num*product)
上面这种是尾递归,做了优化,栈不会增长,因此多少次调用也不会导致栈溢出。
遗憾的是,大多数编程语言没有针对尾递归做优化,Python解释器也没有做优化,所以,即使把上面的fact(n)函数改成尾递归方式,也会导致栈溢出