上节课我们初步了解了什么是函数,并讲了自定义函数的定义方式。Python中的函数如果深入研究还有很多的知识,我们这里只针对青少年编程考级的内容讲一下函数的部分进阶操作。
一、函数的可选位置参数
在讲这两种参数前,先让大家思考一个问题。如果要写一个函数,计算两个数的乘积,我们很容易就能写出来:
deftimes(a,b):c=a*bturnc
那如果让大家写一个函数,计算若干个数的乘积。我们该怎么写呢?乘数的个数不确定,用户可能算2个数的乘积、3个数的乘积,甚至算个数的乘积。
那按照我们之前讲的内容,函数的形参的个数是固定的,有几个形参调用函数时就要就几个实参,那这个函数是不是就没法写了呢?这就要引入一个新的知识:可选位置参数。
可选位置参数(positionalarguments)在形参中使用“*”开头,后面写变量名,大家约定俗成写成“*args”,它可以将实参的多个值以元组的方式传入函数中。
我们看下面的例子:
deffunction(*args):print(args)function(1,2,3)#(1,2,3)
有了可选位置参数,我们可以很好解决前面讲的计算若干个数乘积的问题了,我们看一下代码:
deftimes(*args):p=1foriinargs:p*=iturnpproduct=times(2,3,4,5)print(product)#
可选位置参数和普通的形参还可以同时使用,但是普通的形参必须写在前面,后面写可选位置参数。我们在调用函数时,前面的实参与形参一一对应,最后所有的实参全部赋值给可选位置参数。
我们看下面的例子:
deffunction(a,b,*args):print(a)print(b)print(args)function(1,2,3,4,5,6)#1#2#(3,4,5,6)
二、函数的可选关键词参数
前面我们将了可选位置参数,有时候程序中我们需要给函数加一些关键词,使函数改变某些具体的功能。我们在学习排序的函数时,曾经出现过“verse=True”这样的参数,这就叫可选关键词参数。
可选关键词参数(keywordarguments)是将一个或多个参数以字典的形式传入函数中,在形参中以“**”开头,后面写变量名,大家约定俗成写成“**kwargs”。
我们看下面的例子:
deffunction(**kwargs):print(kwargs)function(name=张三,age=18)#{name:张三,age:18}
可选位置参数和可选关键词参数可以在一个函数中同时使用,可选位置参数必须写可选关键词参数前面。
我们看一个例子:
编写一个函数,被除数为若干个数相加,除数(divisor)函数中加devisor=n指定,如果不指定除数,则除数为1。计算出除法的结果。这个函数可以这样书写:
defdivision(*args,**kwargs):s=sum(args)ifdivisorinkwargs:d=s/kwargs[divisor]else:d=s/1turnd
三、全局变量和局部变量
在Python中,程序最开始的位置的变量称为全局变量,而在函数中定义的变量称为局部变量。全局变量作用的范围是整个函数,而局部变量的作用域是函数内部。
当程序运行时,首先会找程序内部有没有局部变量,如果有则调用;如果没有才去调用全局变量。
我们看下面的代码:
name=Johndeffunction():name=Kateprint(name)function()#Kateprint(name)#John
因为函数内部定义了全局变量,函数内部打印出来的是局部变量Kate。而最后的print()函数是在函数外执行的,打印出来的就是全局变量John。
那如果我们在函数内部要定义全局变量,我们怎么操作呢?我们需要学习一个新的关键字:global。
同样是刚刚的那段代码,我们如果在函数内部的变量中加global关键词,会有什么效果呢?
name=Johndeffunction():globalname=Kateprint(name)function()#Kateprint(name)#Kate
函数中变量name前面加了global关键字,此时函数中的变量name已经变成了全局变量,我们相当于给变量name重新赋值了。
除了全局变量外,函数中如果嵌套函数,内层的函数的变量也无法调用外层函数变量的值。我们看下面的例子,函数的作用是第一次运行函数时打印1,后面每运行一次加2:
defadd():count=1deffun():print(count)count+=2turnfuna=add()a()a()a()
程序运行以后会报错:
UnboundLocalError:localvariablecountfencedbefoassignment
提示局部变量count在定义前使用了。这个问题我们如何解决呢?我们又要学一个新的关键字:nonlocal。
nonlocal关键字的作用是:在函数或局部作用域使用外层(非全局)变量。上面的代码根据需求做一下修改:
defadd():count=1deffun():nonlocalcountprint(count)count+=2turnfuna=add()a()a()a()程序运行结果:
注意:global和nonlocal的区别一定要搞清楚。glocal是在函数中使用全局变量;而nonlocal是在内层函数中使用外层函数中的局部变量。
四、为函数参数和返回值指定类型
Python是动态类型语言,新建变量时不需要声明变量类型,自定义函数的参数和返回值也不需要声明类型。但是在Python3.5之后的版本中,增加了对函数参数和返回值类型指定和检查的功能,新建变量时可以指定类型。
参数类型的书写方式:
argument:type
返回值类型的书写方式:
deffunction()-type:
我们看下面的例子,定义一个函数,计算两个数的乘积:
deftimes(a:int,b:int)-int:c=a*bturncprint(times(4,5))#20
这里面我们指定了参数a和参数b为整数,返回值类型为整数。但是当我们调用函数时,如果参数a输入的是字符串,程序并不会报错:
deftimes(a:int,b:int)-int:c=a*bturncprint(times(abc,3))#abcabcabc
这是因为Python本质上是动态类型语言,函数定义时函数参数和返回值类型的指定只是给程序阅读者一个参考,并不具备实质性的作用。
本节课的内容就到这里,函数嵌套这一块内容还可以引出一个重要的知识点:装饰器。不过在青少年Python考级中不会涉及到这个知识点,这里略去不讲了,有兴趣的同学可以自己找资料研究。
五、课后思考题
1、选择题
运行以下程序,输出的结果是()
x=1defdemo():globalxx=2print(x,end=)demo()print(x,end=)
A.11B.21C.12D.22
2、判断题
调用函数outer(),两次输出变量x的值是不一样的()
defouter():x="local"definner():x="nonlocal"print("inner",x)inner()print("outer:",x)
3、编程题
请定义一个函数,输入若干个数,计算这些数的平均数并保留整数。默认使用四舍五入保留整数,如给定参数appr=floor则使用去尾法保留整数,如给定参数appr=ceil则使用进一法保留整数。
返回值为计算得到的平均数。
(补充知识:math库中有floor()和ceil()两个函数。函数floor()为去尾法、ceil()为进一法。)
4、编程题
BMI指数是国际上用来判断一个人体型是否正常的标准。
BMI=体重÷(身高×身高)
体重单位为kg,升高单位为m。
男性BMI指数的正常范围是20至25,女性的BMI正常范围是18至23。
请定义一个函数,计算BMI是否在正常范围内,在正常范围内返回值为True,不在正常范围内返回值为False。函数有身高、体重两个固定参数。性别(gender)可以输入也可以不输入,默认为男性。可输入女性(female)。
六、上节课思考题答案
1、C
2、参考代码:
defodd_list(lst):lst_new=[]foriinlst:ifi%2==1:lst_new.append(i)print(lst_new)odd_list([4,2,1,4,5,7,9,3])odd_list([8,2,6,8,1,2])odd_list([7,1,8,3,2,5,7])
3、参考代码
trapezoid=lambdaa,b,h:(a+b)*h/2print(trapezoid(1,3,2))#上底为1,下底为3,高为2的梯形