[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 本章小结
墨博士总结:本章你学习了函数的使用,这也是编程中最重要的知识之一。函数用于完成一定的功能,定义好了之后能反复使用;为了能够统一处理类似的情况,函数中引入了变量,也就是参数,省去了定义多个类似函数的麻烦;函数中的形参和实参要对应;函数可以将内部的计算结果返回,用于后续的计算;函数的引入,也使得我们编程的思路发生了改变:先把大问题(功能)划分成多个小问题(函数),一个一个的小功能解决了,大问题就像搭积木一样搭起来也就解决了!