💎一站式轻松地调用各大LLM模型接口,支持GPT4、智谱、星火、月之暗面及文生图 广告
[Toc] # 第8章 函数 博士出差终于回来了!在今天的课程里,墨博士给小墨讲了函数的定义和使用方法。学习Python以来,小墨每次都能听到函数这个词,今天终于弄清楚函数到底是什么以及函数如何定义和使用了。一起来看看吧。 时间:早上9:00 场景:墨馨书屋 墨博士:小墨,我听墨哥哥说你最近学习了很多Python的内容。 小墨:墨哥哥教我的,主要是list和dict这两种数据类型的使用。 墨博士:嗯,这是比较常用的两种数据类型。 小墨:我们今天学习什么呢博士? 墨博士:前面呢你已经接触了很多函数,但这些函数都是Python自带的,我们只管用就行了。今天呢我们就来看看自己如何来定义和使用函数。 我们开始吧! ## 8.1 为什么要有函数 墨博士:还是来做一个练习: 练习: 输出3遍Hello 输出5遍World 输出4遍Hello 输出5遍World 输出3遍Hello 输出5遍World 这个怎么做? 小墨:如果我是第一天学Python,我可能会这样: ``` print('Hello') print('Hello') print('Hello') print('World') print('World') print('World') print('World') print('World') print('Hello') print('Hello') print('Hello') print('Hello') print('World') print('World') print('World') print('World') print('World') print('Hello') print('Hello') print('Hello') print('World') print('World') print('World') ``` 不过现在,我会利用循环,就像这样: ``` for x in range(3): print('Hello') for x in range(5): print('World') for x in range(4): print('Hello') for x in range(5): print('World') for x in range(3): print('Hello') for x in range(3): print('World') ``` 墨博士:做的不错。对于重复的事情,就考虑用循环来解决。 > 墨博士提醒:为方便描述,以上的循环称为循环1、循环2、循环3、循环4和循环5。 但是这段代码还是显得很臃肿,你看第1和5个循环是一样的、第2和第4个循环是一样的,其他两个循环跟它们也差不多。 下面呢我们就给它瘦瘦身。 小墨内心:博士你什么时候也瘦瘦身呢? # [插画:胖博士变成了苗条的瘦博士] 墨博士:假如说我们用一个变量a替换循环1,变量b替换循环2,也即假设: ![](http://7xtc8l.com1.z0.glb.clouddn.com/e6d7d3ea-db45-40f0-9595-84cfd2bd2066.png) ![](http://7xtc8l.com1.z0.glb.clouddn.com/96df9d50-a216-49f2-a86b-811e94e0c4e4.png) 那么,程序会变成这样: ``` a = for x in range(3): print('Hello') b = for x in range(5): print('World') a b for x in range(4): print('Hello') b a for x in range(3): print('World') ``` **注意**:这个只是伪代码,并不符合语法要求,不能独立运行。 小墨,你觉得这样会不会更清晰一点? 小墨:嗯,就像定义变量一样,一个地方定义,多个地方使用,这样就节省了大量重复的代码。 墨博士:同时如果想更改这个功能,只需要在定义的地方更改,其他调用的地方就跟着一块改过了,非常方便。 小墨:这个就是函数吧。 墨博士:是的。不过这个只是思路,接下来我们具体说说函数的定义。 ## 8.2 无参函数的定义和使用 墨博士:函数,又叫方法,表示一个功能,在python中,函数的定义使用def关键字,看如下代码: ``` # 函数的定义 def a(): for x in range(3): print('Hello') ``` > 墨博士提醒:关键字是编程语言里事先定义的,有特别意义的标识符,有时又叫保留字,Python中的if、for、while、def等都是关键字。 这样我们就定义了一个函数,这里的a即表示函数的名字,这个名字是我们自己起的,起名规则就跟变量名一样。第3、4两行称为函数的函数体,函数定义之后,我们就可以把函数名代替函数体去使用了,比如: ``` # 函数的定义 def a(): for x in range(3): print('Hello') # 函数的使用 a() a() a() ``` 就会输出9遍Hello。也即使用定义好的函数时,直接使用函数名后加括号就可以了,这里使用了三次a(),相当于使用了三次for循环,也即输出9次Hello。 好,接下来轮到你了小墨,你把输出5遍World也改成函数吧。 小墨:好的。更改代码如下: ``` def a(): for x in range(3): print('Hello') # 新增定义函数b,用于输出5遍World def b(): for x in range(5): print('World') a() b() # 调用函数b() for x in range(4): print('Hello') b() # 调用函数b() a() for x in range(3): print('World') ``` 墨博士:嗯,不错。这个程序比较短,你的函数体只有一个for循环组成,如果一个程序中某个功能使用了很多次,而这个功能本身又是由很多行代码组成,就更能体现使用函数的好处了。 小墨:我明白了,定义函数之后写代码就好像搭积木了,一个函数就是一个积木,积木内部的东西不需要管,搭积木的人只需要一个个的按需去搭建就可以了。最厉害的是这些积木是可以重用的! 墨博士:总结的很好!下面我们继续前进,把输出4遍Hello和3遍Word的for循环也给改造了。 ## 8.3 有参函数的定义和使用 墨博士:上面我们已经定义并使用了函数来替换重复功能,我们发现,循环3和循环1(也就是函数a的函数体)的区别,仅仅是输出Hello次数的区别,如果3也能用a表示,那就更省事了,这就需要我们了解一下参数的概念。 ### 8.3.1 形式参数 墨博士:对于函数a来说,现在的功能是输出3次Hello,如果我想a能输出4次、5次、甚至任意次数的Hello,应该怎么做呢? 我们可以使用变量n替换掉3: ``` # 函数的定义 def a(): for x in range(n): print('Hello') ``` 小墨:不对吧博士,这样的话,变量n没有定义就使用了,不符合语法要求。 墨博士:是的,想要n能使用,需要先定义,这个定义在a后面的()里,如下: ``` # 函数的定义 def a(n): for x in range(n): print('Hello') ``` 这样,一个带参数的方法就定义好了。 这里的n就被称为函数的参数,严格来说是形式参数。 > 墨博士提醒:参与到具体功能中的未知的东西,在方法定义的时候定义在方法名后面的小括号中的参数,称为形式参数,简称形参。 小墨:我也给我的函数加上参数。咦?加了参数之后方法调用出错了。 墨博士:这就需要了解跟形式参数对应的实际参数了。 ### 8.3.2 实际参数 墨博士:当a的定义改变了之后,a的调用方式也要随着改变。由于a后面的小括号中有了一个n,我们在调用a的时候就需要具体指定这个n是多少,比如: ``` a(3) ``` 即将3的值给n,程序会输出3次Hello,而如果这个值为5,则输出5次Hello,以此类推。 这里的3、5等具体值,是函数调用的时候给形式参数赋的具体的值,称为实际参数,简称实参。 小墨:哦原来是这样,形参是方法上定义的变量,实参是给形参变量赋的值。那么原程序就可以改成这样了: ``` def a(n): for x in range(n): print('Hello') def b(n): for x in range(n): print('World') a(3) b(5) a(4) b(5) a(3) b(3) ``` 墨博士:很好。你再想想,这个程序还能不能再改进改进呢? 小墨:嗯……,现在的程序中,其实a函数和b函数功能差不多,一个是打印Hello,一个是打印World,是不是也可以做成变量替换,然后在调用的时候分别赋值为Hello或World? 墨博士:是的,这就是函数多个参数的情况。 ### 8.3.3 多个参数 墨博士:可以定义一个函数,该函数含有两个参数n和s,n表示打印多少次,s表示打印的内容,这样a和b就能合并成一个了。 ``` # 两个参数函数的定义 def a(n, s): for x in range(n): print(s) ``` 既然函数定义时指明了2个形式参数,调用的时候也需要给两个形式参数提供对应的实际参数: ``` a(3, 'Hello') a(5, 'World') ``` 这里的3和5赋值给了n,Hello和World赋值给了s,运行程序输出了3遍Hello和5遍World。 小墨:哇!我们最初的练习也可以再次改进了: ``` def a(n, s): for x in range(n): print(s) a(3, 'Hello') a(5, 'World') a(4, 'Hello') a(5, 'World') a(3, 'Hello') a(3, 'World') ``` 墨博士:比起最初的5个for循环,是不是简洁清晰了很多? > 动动手:定义一个函数,能够计算x的n次方,其中x和n都不确定。 小墨:嗯,参数的作用还真是强大呀! 墨博士:事实上,Python中的参数远比这强大的多,比如我们还可以使用默认参数。 ### 8.3.4 默认参数 墨博士:以上面打印n遍字符串的例子为例,如果大部分时候都是在打印Hello,只有极少数情况才打印World或其他字符,则可以使用默认参数: ``` def print_str(n, s='Hello'): for x in range(n): print(s) # 打印3遍Hello print_str(3) # 打印4遍Hello print_str(4) # 打印5遍World print_str(5, 'World') ``` 注意:这里为了程序的可读性,将方法名a变成了print_str。 这些基本就能满足你现在的大多数需求了,其他如可变长参数、关键字参数等以后再教给你 。 小墨:好的博士,墨哥哥也说过,贪多嚼不烂。 > 动动手:将计算x的n次方的程序改为n默认值为2 ## 8.4 有返回值的函数的定义和使用 墨博士:我们再来看一下函数的返回值的用法。比如现需要定义一个函数,计算x的绝对值并输出。程序如下: ``` def my_abs(x): if x >= 0: print(x) else: print(-x) ``` 这里只是单纯的将数值使用print输出,如果我想通过my_abs函数计算x的绝对值后,还能得到这个绝对值做其他事情,比如乘以100,应该如何做呢? 这就需要使用return语句了。 ### 8.4.1 return 墨博士:return语句,用在函数中,表示将函数的计算结果“返回”,此时可以拿一个变量接收函数的返回值。比如: ``` def my_abs(x): if x >= 0: return x else: return -x # 接收函数的返回值 n = my_abs(-4) # 做后续其他处理 print(n * 100) ``` 小墨:哦这样我们就能拿到函数的执行结果了。但是我想到一个问题,如果一个函数中的两个数我都想要拿出来,该怎么办? 墨博士:你忘了list是干嘛的了?你可以把两个数放到一个list中,然后将这个list返回,在外面再从list中把两个数取出来就行了。 事实上,在Python中,直接返回多个值也是可以的,看下面代码: ``` def my_return(): return 1, 2 a = my_return() print(a) ``` 输出结果是(1,2) 小墨:这个也是把1和2作为一个整体拿出来了呀,那我如何才能分别拿到1和2呢? 墨博士:你看输出的1和2外面有个小括号,这个呢说明是Python中的tuple类型。 tuple,中文称为元组,相当于一种特殊的list。它的特殊之处在于初始化之后就不能改变了。 ``` # list使用[]初始化元素,tuple使用()初始化元素。 names = ('墨小小', '墨妹妹', '墨大元') for name in names: print(name) for i in range(len(names)): print(names[i]) ``` 由于元素内容不能修改,tuple并没有像list一样提供append()、insert()、pop()等用于添加、插入或删除的方法,当然也不能通过下标取元素的方式修改。 小墨:好的,我记住了。 > 墨博士提醒:Python中可以使用type函数看任意变量的类型,如下: ``` print(type(a)) ``` 输出: ``` <class 'tuple'> ``` > 这就说明a是tuple类型。 ### 8.4.2 return注意事项 墨博士:在使用return的时候需要注意一些事项。比如: ``` def a(): for i in range(4): if i == 2: return i print(i) x = a() ``` 结果会输出什么? 小墨:我猜是输出0、1、2和3。 墨博士:实际运行,只会输出0和1。 小墨:为什么会这样呢?是return之后for循环就结束了吗? 墨博士:函数体内部的语句在执行时,一旦执行到“return”,就返回return后面的结果,同时函数也就执行完毕,此时如果“return”后面还有其他内容,也不再执行。 小墨:哦也就是整个方法就结束了。 墨博士:是的。有时候这一点也被用于单纯的结束函数。比如刚才的代码,如果我们并不想要函数中返回的i,只是想在i为2的时候结束方法。可以return后面什么都不加。 ``` def a(): for i in range(4): if i == 2: return print(i) ``` 小墨:这样也可以? 墨博士:是的,算是方法的一个小技巧吧。好了,函数的内容就先说这么多啦。 ## 8.5 本章小结 墨博士总结:本章你学习了函数的使用,这也是编程中最重要的知识之一。函数用于完成一定的功能,定义好了之后能反复使用;为了能够统一处理类似的情况,函数中引入了变量,也就是参数,省去了定义多个类似函数的麻烦;函数中的形参和实参要对应;函数可以将内部的计算结果返回,用于后续的计算;函数的引入,也使得我们编程的思路发生了改变:先把大问题(功能)划分成多个小问题(函数),一个一个的小功能解决了,大问题就像搭积木一样搭起来也就解决了!