作者:凡希
来源:我将在南极找寻你
零基础玩转Python函数
开篇
考虑这么一个问题:
求解1到4之和
这题其实很简单啦,你应该能很轻松的写出下面的代码:
sum=0
for i in range(1,5):
sum+=i
print('1+2+3+4=',sum)
bingo!
那如果问题改为求解1到10之和呢?
也不难对吧,只需对range()稍作修改:
sum=0
for i in range(1,11):
sum+=i
print('1+2+...+10=',sum)
那如果问题改为求解1到100,1到1000之和呢?
同样是修改range()中的数字即可!
仔细思考一下,你会发现,上面的几个问题其实可以归纳为一个问题:求和
每个问题的解答代码其实都只是更改了range()中的一个数字
如果对于每一个问题,我们都去写一段上面的代码,那简直是灾难!因为会出现大量重复的代码。
所以,函数应运而生!
初识函数
函数的结构如下:

其中的def是关键字,func是可自定义的函数名,x是函数的参数,可以有多个(这里的举的栗子只有一个),函数体内书写你的代码,这段代码规定了函数要做什么事。
如果你是初学者,看了上面的定义之后可能还是一头雾水。没关系,看个栗子感受一下:
我们将开篇中提到求和问题写成函数的形式:

我们给函数取了名字叫做get_sum,给函数设置了一个参数x
函数的功能是求解1到x之和
注意,写完这个函数之后,什么也看不到,因为你只是定义好了函数,而函数只有在被调用时才会执行函数体内的语句
现在来尝试调用函数,我们分别给x传入4和10,用于求解1到4之和与1到10之和:
#求解1到4之和
get_sum(4)
#求解1到10之和
get_sum(10)
输出
1+2+...+4= 10
1+2+...+10= 55
看,使用了函数之后,代码变得简洁起来。
函数的返回值
其实,每个函数都有返回值。在关键字return后面写需要返回的变量名。如果函数没有用return,那默认返回None。
返回值也是个值,所以可以将这个值赋值给变量,此时称这个变量是用来接收返回值的变量。
我们上面的求和问题中,函数是没有写return的,因此函数的返回值应该是None,我们来验证这一点:
#求解1到4之和
c=get_sum(4)
print(c)
输出
None
我们可以给get_sum函数指定返回值,比如可以指定返回求和结果sum,于是我们可以稍微修改下函数的定义:

此时,再次调用函数:
#求解1到4之和
c=get_sum(4)
print(c)
输出
10
多个参数
函数的参数可以有多个,比如求解两数之和,我们可以这样定义函数:
#求解两数之和,即:x+y
def add(x,y):
return x+y
这里的参数有两个,分别是x和y。
多个返回值
函数的返回值也可以有多个,比如同时求解两数之和与两数之差:
def cal(x,y):
add_result=x+y
minus_result=x-y
return add_result,minus_result
这里分的返回值是两数之和与两数之差。
此时我们可以用一个或者两个变量来接收返回值:
【用两个变量接收返回值】这个很符合我们的思维,因为函数的返回值是两个,所以用两个变量来接收返回值
add,minus=cal(1,3)
print(add,minus)
输出
4 -2
【用一个变量接收返回值】
result=cal(1,3)
print(result)
输出
(4, -2)
返回值是一个元组,Python的灵活性在这里又一次被体现。
形参与实参
def get_sum(x):
sum=0
for i in range(1,x+1):
sum+=i
print(sum)
#求解1到z之和
z=4
get_sum(z)
在这个栗子中,get_sum函数中()内的x是形参,而z是实参。
顾名思义,形参就是形式上的参数,在函数定义好之后,形参并没有任何实际值。只有在调用函数时,才将实参传给形参,此时形参将得到的值收下,之后函数内部凡是出现形参名字的地方都具有传入的实参的值。
总结来说:
形参是函数定义时的参数,实参是函数调用时传给函数的参数
你还要了解,形参和实参是可以同名的,因此上例中的z即使改名为x也可以得到相同的结果。
请再次体会一下上面的栗子,以加深理解。
默认参数
假设要录入"南极小学"六年级一班全体同学的姓名、年龄以及出生地信息,将每个同学的信息作为一个字典,将所有同学的信息一起存入列表。
为了方便,假设该班共有3个同学,则可写出如下代码:
lis=[]
def func(name ,age,place):
person={}
person['name']=name
person['age']=age
person['place']=place
lis.append(person)
func('Bob',5,'南极洲')
func('Alice',6,'南极洲')
func('Barry',7,'南极洲')
#遍历列表lis,打印所有同学的信息
for item in lis:
print(item)
输出
{'name': 'Bob', 'age': 5, 'place': '南极洲'}
{'name': 'Alice', 'age': 6, 'place': '南极洲'}
{'name': 'Barry', 'age': 7, 'place': '南极洲'}
仔细观察,你会发现,每个同学的出生地都是"南极洲"。既然相同,那就可以将形参place设置为默认参数,默认值为"南极洲",调用函数传参时就可以不写place了,这样做可以减少无谓的工作量。
于是代码如下:
lis=[]
def func(name ,age,place='南极洲'):
person={}
person['name']=name
person['age']=age
person['place']=place
lis.append(person)
#只需传入name和age,place使用默认值'南极洲'
func('Bob',5)
func('Alice',6)
func('Barry',7)
#打印所有信息,会得到和上面相同的结果
for item in lis:
print(item)
当然,如果此时突然新转来了一个同学“大猫”到该班中,并且大猫同学出生在"北冰洋",那么就不能使用默认的place了。解决方法很简单,只需像正常传参那样给place传入"北冰洋"即可,代码如下:
lis=[]
def func(name ,age,place='南极洲'):
person={}
person['name']=name
person['age']=age
person['place']=place
lis.append(person)
func('Bob',5)
func('Alice',6)
func('Barry',7)
func('大猫',5,'北冰洋')
#打印所有信息
for item in lis:
print(item)
输出结果
{'name': 'Bob', 'age': 5, 'place': '南极洲'}
{'name': 'Alice', 'age': 6, 'place': '南极洲'}
{'name': 'Barry', 'age': 7, 'place': '南极洲'}
{'name': '大猫', 'age': 5, 'place': '北冰洋'}
需要注意的是,在定义一个函数时,如果存在位置参数(这里的name和age就是位置参数,位置参数的详细讲解就在下一部分),那么必须将默认参数放到最后,就像本栗中,将默认参数place放在了最后。
def func(name ,age,place='南极洲'):
...
位置参数
其实,在上一部分【默认参数】的栗子中,name和age就是位置参数。
对于位置参数来说,在传参时,各个参数的实际值与其位置下标必须一一对应,否则就可能导致程序输出信息有误或者程序直接报错。
比如我们在给大猫同学录入信息时可以这样写:
func('大猫',5,'北冰洋')
当然也可以指明'place':
func('大猫',5,place='北冰洋')
但绝对不能更换name和age的位置,否则年龄就和姓名颠倒了,看下面的反例:
假设我们在传参时互换了name和age的位置
func(5,'大猫',place='北冰洋')
则输出结果中关于大猫同学的信息就会变为:
{'name': 5, 'age': '大猫', 'place': '北冰洋'}
这表示的是一个叫5的同学,年龄为'大猫',闹笑话了吧~
而如果在其他程序中也犯这样的错误,可能不只是闹笑话,程序可能直接崩溃(因为有些参数类型不同,在函数内部的语句执行时不能对应到相应的数据类型,从而导致程序报错)。
关键字参数
在传参时,如果不单单传入值,还将对应的参数名字也一并传入,那么这就是关键字参数了。
还是拿南极小学的栗子来说明,如果我们在录入大猫同学的信息时这样传参:
func(name='大猫',age=5,place='北冰洋')
由于使用了关键字参数,因此也可以这样传参:
func(age=5,name='大猫',place='北冰洋')
看,调换了name和age的位置,仍然可以!
甚至你也可以调换默认参数place的位置(此时是在修改默认参数的前提下进行的,在这种情况下,默认参数其实也算是一个关键字参数):
func(name='大猫',place='北冰洋',age=5)
但是,当位置参数和关键字参数同时存在时,位置参数必须在关键字参数前面。
举个反例:
func(age=5,'Bob')
这个写法是不被Python允许的,因为关键字参数age放在了位置参数name前面。
可变参数
所谓可变参数,就是指在定义函数时,参数的个数并没有被写死,而是可以动态变化的。在上面所介绍的栗子中,其实都是不可变参数,因为参数的个数在定义函数的那一刻就被固化了
正如不可变参数可分为位置参数和关键字参数那样,可变参数也有可变位置参数和可变关键字参数。
可变位置参数前面加一个*,可变关键字参数前面加两个*。

注意这里的args和kwargs是约定俗成的名字,你也可以改成任何合法的名字,但不推荐。
传入可变位置参数的值会被保存在一个元组中,而传入可变关键字参数的值会被保存在一个字典中。
下面还是举两个栗子来分别说明:
1.【可变位置参数实例】
def add(a,b):
print(a+b)
这个函数的功能是求解两数之和,如果我们想要求大于两个的数字之和,比如3数之和,4数之和等,由于不确定到底有多少个数,因此可以在定义函数时设置一个可变参数。
那是设置可变位置参数还是可变关键字参数呢?
其实这个要根据实际情况以及方便性等来确定。我们这里只是求解多个数字的和,并不涉及到其他诸如信息存取的操作,因此为了更方便,可以设置可变位置参数。
于是,最终的函数定义如下:
def add(a,b,*args):
sum=a+b
print('args:',args)
for i in args:
sum+=i
print('求和结果为:',sum)
尝试调用函数:
add(1,2,3,4,5)
得到如下输出:
args: (3, 4, 5)
求和结果为: 15
2.【可变关键字参数实例】
还是拿南极小学那个栗子来说,如果不单单可以录入name、age和place,而且还可以录入每个同学的爱好hobby、未来想从事的的职业job,当然新增的这两个是可选的,同学可以只录入hobby,可以只录入job,可以同时录入两者,也可以同时不录入这两者。在这个场景下,就可以可变关键字参数了。

得到的输出结果如下:

在上面的代码中,Bob同学只录入了必选项,而其余三名同学都或多或少的录入了可选项,因此只有Bob同学的kwargs为空字典。
看完以上所讲内容,你已经初步学会使用函数了,接下来就是多加练习,多敲代码,加油吧!
---------End---------
关注后回复“w”,加我私人微信

“分享”和“在看”是更好的支持!
本文从基础开始,深入浅出地介绍了Python函数的定义、使用及高级特性,包括参数传递、返回值、可变参数等,适合Python初学者。





177

被折叠的 条评论
为什么被折叠?



