07-函数
概述:本文主要分析Python中的函数
一、定义函数
语法格式
1 def funcName(params): 2 code block
函数的返回值通过 return 语句返回。如果没有 return 语句,函数执行完毕后也会返回结果,只是结果为 None。return None 和 return 是相同的。
空函数
如果函数还没想好怎么写,可以将函数体写作 pass,这是一个占位符,以便代码可以先运行起来。
参数检查
Python 解释器能检查出函数参数个数不对的问题,并抛出 TypeError。但是 Python 解释器不能检查参数类型,这需要我们自己写入检查机制。
数据类型检查可以用内置函数 isinstance() 实现:
1 def my_abs(x): 2 if not isinstance(x, (int, float)): 3 raise TypeError('bad operand type') 4 if x >= 0: 5 return x 6 else: 7 return -x
返回多个值
Python 中可以使用 return 语句返回多个值,例如: return x, y 。接受返回值时,也用两个变量分别接收: a, b = move()。
但实际上,Python 是将多个值放在一个 tuple 中再返回,所以返回的还是一个值。从语法上来说,返回一个 tuple 可以省略括号,多个变量也可以同时接收一个 tuple。
二、调用函数
我们只要知道函数的名称和参数,即可调用函数。如果不清楚函数的具体用法,可以在交互命令行通过 help(func) 来查看信息。
调用函数的时候,如果传入的参数数量不对,则会报 TypeError 的错误,并给出错误信息。
数据类型转换
1 int(param) # 将其他数据类型转换为 int 2 float(param) # 将其他数据类型转换为 float 3 str(param) # 将其他数据类型转换为 str 4 bool(param) # 将其他数据类型转换为 bool 5 hex() # 将整数转换为十六进制的字符串
三、函数的参数
位置参数
函数定义时定义的参数,就是位置参数。调用函数时,传入的值按照位置顺序依次赋给参数。譬如 power(x, n) 中,x 和 n 就是位置参数。
默认参数
我们在函数定义时,可以给参数指定一个默认值。如果调用时没有传入此参数的值,这个参数就会使用默认值,而不会抛出 TypeError。
默认参数可以简化函数的调用,但是需要注意以下两点:
-
- 必选参数在前,默认参数在后,否则会报错(如果默认参数在前面,如何确定传进来的参数是给默认参数的,还是给位置参数的?)
- 如何设置默认参数(通常把经常变化的参数放在前面,作为普通的位置参数。很少需要变化的参数放在后面,作为默认参数)
默认参数降低了调用函数的难度:对于很少变化的参数而言,我们在调用时不用对它传参,使用默认参数即可。只有少数的情况需要修改,此时再给默认参数传入新数据。
有多个默认参数时,有两种传参的方式:
-
- 按函数定义的顺序,提供默认参数(如果传入的参数个数不够,后面的仍用默认值)
- 不按函数定义的顺序,提供默认参数(此时要把参数名写上,以确定这个数据是给哪个参数的)。譬如:enroll('Adam', 'M', city='Tianjin')
默认参数必须指向不变对象,否则会引起错误。因为默认参数本身是个变量,如果我们改变了它的内容,下次调用时,默认参数的内容就变了:
def add_end(L=[]): L.append('END') # L的内容改变了 return L
我们可以令 L = None,指向不变的对象,这样就没有问题了。
可变参数
所谓可变参数,就是指传入的参数个数是可变的。可变参数定义时,要在前面加上 *,如: def calc(*numbers)。在函数内部,参数 numbers 收到的是一个 tuple。
如果我们已经有了一个 list 或 tuple,就不用一个一个传参了。我们可以直接在前面加一个 *,把 list 或 tuple 变成可变参数传进去:
nums = [1, 2, 3]
calc(*nums)
关键字参数
关键字参数允许我们传入 0 个或人一个含参数名的参数,这些关键字参数在函数内部自动组装成一个 dict。在定义函数时,关键字参数前要加 **。
1 def person(name, age, **kw): 2 print('name: ', name, 'age: ', age, 'other: ', other)
在调用时,可以只传入必选参数,也可以传入任意个关键字参数:
1 person('Bob', 35, city='Beijing') 2 person('Adam', 45, gender='M', job='Engineer')
我们也可以先组装出一个 dict,然后把它转换为关键字参数传进去:
1 extra = {'city': 'Beijing', 'job': 'Engineer'} 2 person('Jack', 24, **extra)
**extra 表示把 extra 这个 dict 的所有 key-value 用关键字参数传入到函数的 **kw 参数,kw 将获得一个 dict。注意:kw 获得的 dict 是 extra 的一份拷贝,对 kw 的改动不会影响到函数外的 extra。
命名关键字参数
关键字参数到底传入到哪里?这需要在函数内部通过 kw 检查。例如检查是否有 city 和 job 参数:
1 def person(name, age, **kw): 2 if 'city' in kw: 3 pass 4 if 'job' in kw: 5 pass 6 print('name: ', name, 'age: ', age, 'other: ', kw)
但是调用者还是可以不受限制地传入参数,如果要限制关键字参数的名字,就可以用命名关键字参数。命名关键字参数需要一个特殊分隔符 *,* 后面的参数都被视作命名关键字参数。例如,只接受 city 和 job 作为关键字参数:
1 def person(name, age, *, city, job): 2 pass
如果函数定义中已经有了一个可变参数,后面跟着的命名关键字参数就不需要再写特殊分隔符 * 了。例如:
1 def person(name, age, *args, city, job): 2 pass
命名关键字参数必须传入参数名,否则会报错。
命名关键字参数可以有缺省值,调用时可以不传入具有缺省值的参数,从而简化调用:
1 def person(name, age, *, city='Beijing', job): 2 pass
参数组合
Python 中的函数可以组合使用必选参数、默认参数、可变参数、关键字参数和命名关键字参数,但必须按上述顺序定义。我们也可以将参数写入 tuple 和 dict,然后调用上述函数:
1 def f1(a, b, c=0, *args, **kw): 2 print('a =', a, 'b =', b, 'c =', c, 'args =', args, 'kw =', kw) 3 4 args = (1, 2, 3, 4) 5 kw = {'d': 99, 'x': '#'} 6 f1(*args, **kw)