Day14、15:函数
在Python中,定义一个函数要使用def语句,依次写出函数名、括号、括号中的参数和冒号:。
def my_abs(x):
if x>=0:
return x
else:
return -x
空函数
如果想定义一个什么事也不做的空函数,可以用pass语句:
def nop():
pass
pass语句什么都不做,那有什么用?实际上pass可以用来作为占位符,比如现在还没想好怎么写函数的代码,就可以先放一个pass,让代码能运行起来。
pass还可以用在其他语句里,比如:
if age >= 18:
pass
参数检查
修改my_abs的定义,对参数类型做检查,只允许整数和浮点型的参数。
数据类型的检查可以用内置函数isinstance()实现:
def my_abs(x):
if not isinstance(x, (int, float)):
raise TypeError('bad operand type')
if x >= 0:
return x
else:
return -x
返回多个数
支持返回多个值。
import math
def move(x,y):
nx = x+math.cos(y)
ny = y-math.sin(x)
return nx,ny
r=move(10,122)
print(r)
其实返回的是一个tuple!
Python的函数定义非常简单,但灵活度却非常大。除了正常定义的必选参数外,还可以使用默认参数、可变参数和关键字参数,使得函数定义出来的接口,不但能处理复杂的参数,还可以简化调用者的代码。
默认参数
可以在定义函数参数时,给参数一个初始值,调用时可以不给该参数赋值,函数会使用参数的默认值。
def power(x,n=2):
s=1
while n>0:
n=n-1
s=s*x
return s
power(3) >>> 9
power(3,3) >>> 27
设置默认参数时,有几点要注意:
一是必选参数在前,默认参数在后,否则Python的解释器会报错。
二是如何设置默认参数。
当函数有多个参数时,把变化大的参数放前面,变化小的参数放后面。变化小的参数就可以作为默认参数。
用默认参数的好处:比如要通过调用一个函数输入一组数据,该数据有四个参数,而大部分人的后面两个参数相同,这时候用默认参数就可以节省大量时间。
当不按顺序提供部分默认参数时,需要把参数名写上。
例:
# 定义
def enroll(name,gender,age=22,city="tianjin")
# 调用 ,不按顺序提供参数
enroll('Bob','M',city='anqing')
可变参数
当参数个数不确定时,我们可以把参数作为一个list或tuple传进来。
def calc(numbers):
sum=0
for n in numbers:
sum=sum+n*n
return sum
调用时,需要先组装出list或tuple。
calc([1,2,3])
如果利用可变参数,这样写:
def calc(*numbers):
sum=0
for n in numbers:
sum=sum+n*n
return sum
只需要在参数名前加个*
调用时:
calc(1,2,3)
还有一种情况:
nums=[1,2,3]
#调用一个已定义好的list或tuple
calc(*nums)
#在名字前加*变为可变参数。
*nums表示把nums这个list的所有元素作为可变参数传进去。这种写法相当有用,而且很常见。
关键字参数
可变参数允许传入0个或任意个参数,这些参数调用时自动组装成list。
关键字参数允许传入0个或任意个含参数名的参数,这些关键字参数自动组装为一个dict(键——值)
加两个**
# 只传入可变参数
def person(name,age,**kw):
print('name',name,'age',age,'others:',kw)
print('Adam',22)
`
# 传入任意个数的关键字参数
person('Bob',23, city ='Beijing')
person('Bob',23, city ='Beijing',gender='M')
关键字参数有什么用?它可以扩展函数的功能。比如,在person函数里,我们保证能接收到name和age这两个参数,但是,如果调用者愿意提供更多的参数,我们也能收到。试想你正在做一个用户注册的功能,除了用户名和年龄是必填项外,其他都是可选项,利用关键字参数来定义这个函数就能满足注册的需求。
命名关键字参数
如果要限制关键字参数的名字,就可以用命名关键字参数,例如,只接收city和job作为关键字参数。这种方式定义的函数如下:
def person(name,age,*,city,job)
print(name,age,city,job)
person('bob', 23, city='anqing', job='engineer')
如果函数定义中已经有了一个可变参数,后面跟着的命名关键字参数就不再需要一个特殊分隔符*了:
def person(name,age,*args,city,job):
print(name,age,args,city,job)
person('bob', 20,1, city='Beijing', job='Engineer')
当命名关键字参数有默认值时,调用时可以省略该参数的赋值。
def person(name,age,*args,city='NanJing',job):
print(name,age,args,city,job)
person('bob', 20,1, job='Engineer')
参数组合
在Python中定义函数,可以用必选参数、默认参数、可变参数、关键字参数和命名关键字参数,这5种参数都可以组合使用。但是请注意,参数定义的顺序必须是:必选参数、默认参数、可变参数、命名关键字参数和关键字参数。
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)
f1(1,2)
f1(1,2,3)
f1(1,2,3,'a','b')
f1(1,2,3,'a','b',x=99)
f2(1,2,3,d=99,x=99)
还可以通过一个tuple和dict调用上述函数:
# 用list,tuple和dict调用:
args=[1,2,3,4]
kw={'d':99,'x':'#'}
f1(*args,**kw)
# 用tuple和dict调用
args=(1,2,3)
kw={'d':99,'x':'#'}
f2(*args,**kw)
所以对于任何函数,都可以通过类似func(*args, **kw)的形式调用它,无论它的参数是如何定义的。
练习:
# 以下函数允许计算两个数的乘积,请稍加改造,变成可接收一个或多个数并计算乘积:
def mul(*args):
if len(args) == 0:
raise TypeError('请输入值:')
s = 1
for n in args:
s = s*n
return s
print(mul(1, 2, 3))
print(mul(1, 2, 3, 4))
小结
-
*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(**{'a': 1, 'b': 2})。 -
使用
*args和**kw是Python的习惯写法,当然也可以用其他参数名,但最好使用习惯用法。 -
命名的关键字参数是为了限制调用者可以传入的参数名,同时可以提供默认值。
-
定义命名的关键字参数在没有可变参数的情况下不要忘了写分隔符
*,否则定义的将是位置参数。
递归函数
汉诺塔:
def move(n,a,b,c):
if n==1:
print(a,' --> ', c)
else:
move(n-1,a,c,b)
move(1,a,b,c)
move(n-1,b,a,c)

浙公网安备 33010602011771号