函数调用
Python内置了很多有用的函数可以直接调用。可以在交互式命令行通过help(abs)查看abs函数的帮助信息。
调用函数的时候,如果传入的参数数量不对,会报TypeError的错误,并且Python会明确地指出:abs()有且仅有1个参数,但给出了两个:
1 | abs(1, 2) |
如果传入的参数数量是对的,但参数类型不能被函数所接受,也会报TypeError的错误,并且给出错误信息:str是错误的参数类型:
1 | abs('a') |
函数定义
在Python中,定义一个函数要使用def语句,依次写出函数名、括号、参数和冒号,然后,在缩进块中编写函数体,函数的返回值用return语句返回。
以自定义一个求绝对值的my_abs函数为例:
1 | def my_abs(x): |
请注意,函数体内部的语句在执行时,一旦执行到return时,函数就执行完毕,并将结果返回。如果没有return语句,函数执行完毕后也会返回结果,只是结果为None。return None可以简写为return。
函数返回多值
math包提供了sin()和cos()函数,用import引用它:
1 | import math |
这样就可以同时获得返回值:
1 | x, y = move(100, 100, 60, math.pi / 6) |
但其实Python函数返回的仍然是单一值:
1 | r = move(100, 100, 60, math.pi / 6) |
用print打印返回结果,返回值是一个tuple!
但是,在语法上,返回一个tuple可以省略括号,而多个变量可以同时接收一个tuple,按位置赋给对应的值,所以,Python的函数返回多值其实就是返回一个tuple。
递归函数
在函数内部,可以调用其他函数。如果一个函数在内部调用自身本身,这个函数就是递归函数。
1 | # 汉诺塔 |
递归函数的优点是定义简单,逻辑清晰。理论上,所有的递归函数都可以写成循环的方式,但循环的逻辑不如递归清晰。
使用递归函数需要注意防止栈溢出。在计算机中,函数调用是通过栈(stack)这种数据结构实现的,每当进入一个函数调用,栈就会加一层栈帧,每当函数返回,栈就会减一层栈帧。由于栈的大小不是无限的,所以,递归调用的次数过多,会导致栈溢出。
定义默认参数
Python自带的int()函数,其实就有两个参数,既可以传一个参数,又可以传两个参数。int()函数的第二个参数是转换进制,如果不传,默认是十进制 (base=10)。
1 | int('123') |
函数的默认参数的作用是简化调用,只需要把必须的参数传进去。但是在需要的时候,又可以传入额外的参数来覆盖默认参数值。
定义一个计算x的N次方的函数如下:
1 | def power(x, n): |
假设计算平方的次数最多,就可以把n的默认值设定为2:
1 | def power(x, n=2): |
由于函数的参数按从左到右的顺序匹配,所以默认参数只能定义在必需参数的后面:
1 | # OK: |
定义可变参数
如果想让一个函数能接受任意个参数,可以定义一个可变参数:
1 | def fn(*args): |
可变参数的名字前面有个*号,可以传入0个、1个或多个参数:
1 | fn() #() |
Python解释器会把传入的一组参数组装成一个tuple传递给可变参数,因此,在函数内部,直接把变量args看成一个tuple就好了。定义可变参数的目的也是为了简化调用。