递归函数:
在函数内部,可以调用其他函数。如果一个函数在内部调用自身本身,这个函数就是递归函数。
举个例子,我们来计算阶乘 n! = 1 * 2 * 3 * ... * n,用函数 fact(n)表示,可以看出:
fact(n) = n! = 1 * 2 * 3 * ... * (n-1) * n = (n-1)! * n = fact(n-1) * n
所以,fact(n)可以表示为 n * fact(n-1),只有n=1时需要特殊处理。
于是,fact(n)用递归的方式写出来就是:
def fact(n): if n==1: return 1 return n * fact(n - 1)上面就是一个递归函数。可以试试:
>>> fact(1) 1 >>> fact(5) 120
如果我们计算fact(5),可以根据函数定义看到计算过程如下:
===> fact(5) ===> 5 * fact(4) ===> 5 * (4 * fact(3)) ===> 5 * (4 * (3 * fact(2))) ===> 5 * (4 * (3 * (2 * fact(1)))) ===> 5 * (4 * (3 * (2 * 1))) ===> 5 * (4 * (3 * 2)) ===> 5 * (4 * 6) ===> 5 * 24 ===> 120使用递归函数需要注意防止栈溢出 。在计算机中,函数调用是通过栈(stack)这种数据结构实现的,每当进入一个函数调用,
栈就会加一层栈帧,每当函数返回,栈就会减一层栈帧。由于栈的大小不是无限的,所以,递归调用的次数过多,会导致栈溢出。可以试试计算 fact(10000)。
定义默认参数
函数的默认参数的作用是简化调用,你只需要把必须的参数传进去。但是在需要的时候,又可以传入额外的参数来覆盖默认参数值。
我们来定义一个计算 x 的N次方的函数:
def power(x, n): s = 1 while n > 0: n = n - 1 s = s * x return s
print power(2,3)#ok
print power(2)#error
由于函数的参数按从左到右的顺序匹配,所以默认参数只能定义在必需参数的后面:
# OK: def fn1(a, b=1, c=2): pass # Error: def fn2(a=1, b): pass
任务
请定义一个 greet() 函数,它包含一个默认参数,如果没有传入,打印 'Hello, world.',如果传入,打印 'Hello, xxx.'
-
?不会了怎么办
-
默认参数的默认值可以设定为'world'
参考代码:
def greet(name='world'): print 'Hello, ' + name + '.' greet() greet('Bart')
Hello, world. Hello, Bart.定义可变参数
如果想让一个函数能接受任意个参数,我们就可以定义一个可变参数:
def fn(*args): print args
可变参数的名字前面有个 * 号,我们可以传入0个、1个或多个参数给可变参数:
>>> fn() () >>> fn('a') ('a',) >>> fn('a', 'b') ('a', 'b') >>> fn('a', 'b', 'c') ('a', 'b', 'c')
可变参数也不是很神秘,Python解释器会把传入的一组参数组装成一个tuple传递给可变参数,因此,在函数内部,直接把变量 args看成一个 tuple 就好了。
定义可变参数的目的也是为了简化调用。假设我们要计算任意个数的平均值,就可以定义一个可变参数:
def average(*args): ...
这样,在调用的时候,可以这样写:
>>> average() 0 >>> average(1, 2) 1.5 >>> average(1, 2, 2, 3, 4) 2.4
任务
请编写接受可变参数的 average() 函数。
-
?不会了怎么办
-
可变参数 args 是一个tuple,当0个参数传入时,args是一个空tuple。
参考代码:
def average(*args): sum = 0.0 if len(args) == 0: return sum for x in args: sum = sum + x return sum / len(args) print average() print average(1, 2) print average(1, 2, 2, 3, 4)
或者
-
def average(*args):
-
-
if len(args)!=0:
return sum(args)*1.0/len(args)
else:
return 0.0