python - 函数

自带函数

比如说当我们需要实现“打印”这个功能,我们会用到print();当我们需要实现“获取数据长度”这个功能,我们会要到len()。这些都是设定好了,可以直接拿过来就用的功能,这就叫做“组织好的代码”。

函数(Function)能实现的功能从简单到复杂,各式各样,但其本质是相通的:“喂”给函数一些数据,它就能内部消化,给你“吐”出你想要的东西。

函数后面都跟了个括号。而括号里放的东西,也就是我们需要输入的数据,它在函数中被称作【参数】。【参数】指向的是函数要接收、处理怎样的数据。

比如print()函数的括号里可以放不同的参数,根据你放的参数不同,print()函数会帮你在屏幕上显示不同的内容。

print('Hello World')
print('万物的终极答案')
print(42)

括号里面的字符串和整数,都是print() 函数的参数。

定义函数

def 函数名(参数1,参数2...参数n):
    函数体
    return 语句

举个栗子:

def greet(name):
    print(name+'早上好')
    return

(打招呼的英文是greet,你写say_hello或别的也行,其实理论上你随便起什么都可以,但别人也看得懂是最好的啦。)

来一起读代码。第1行:def的意思是定义(define),greet是【函数名】(自己取的),再搭配一个括号和冒号,括号里面的name是参数(参数名也是自己取)。

第2行:def下一行开始缩进的代码是函数要实现的功能,也叫【函数体】。这里的函数体展现出的功能就是:打印出“name+ 早上好”这句话。

第3行:一个简单的return。函数内部一旦遇到return语句,就会停止执行并返回结果。没有return语句的函数,Python也会在末尾隐性地加上return None,即返回None值(return None可以简写为return。)所以你也会看到,我们接下来的很多例子是省略了return语句的。

定义函数的语法并不难,但有些注意事项一开始要特别注意,我标记在下面代码块的注释里,请你一定仔细阅读下。

#函数名:最好是取体现函数功能的名字,一般用小写字母和单下划线、数字等组合
def greet(name):
#参数:根据函数功能,括号里可以有多个参数,也可以不带参数,命名规则与函数名相同
#规范:括号是英文括号,后面的冒号不能丢
    print(name+'早上好')
#函数体:函数体就是体现函数功能的语句,要缩进,一般是四个空格
    return

看到第三行注释,你可能会有点疑问,怎么括号里可以有参数,又能没有参数?接下来我举个小例子,你可以对比一下。

#第一个函数
def pika1():
    print('我最喜爱的神奇宝贝是皮卡丘')

#第二个函数
def pika2(name):
    print('我最喜爱的神奇宝贝是'+name)
    
#第三个函数
def pika3(name,person):
    print('我最喜爱的神奇宝贝是'+name)
    print('我最喜爱的驯兽师是'+person)

这几个函数的功能都是打印出句式相同的话,区别在于第一个函数总是输出固定的一句话,所以不需要带参数。

而第二个函数需要参数name的参与,所以括号里需要带上name,第三个函数则需要两个参数来完成功能。所以说,参数的数量需要视函数想要实现什么功能来设置。

定义完函数的下一步就是调用函数,召唤神奇宝贝的时刻到了。

调用函数

在Python里,就是输入函数名和参数对应的值。就像这样:

def pika2(name):
    print('我最喜爱的神奇宝贝是'+name)
pika2('皮卡丘')  #调用函数,输入函数名pika()并输入参数'皮卡丘'
pika2('喷火龙')  #调用函数,输入函数名pika()并输入参数'喷火龙'

请阅读代码并运行一下:

def pika1():
    print('我最喜爱的神奇宝贝是皮卡丘')
#该函数没有参数,直接调用函数名。记得英文括号一定不能少
pika1()

def pika2(name):
    print('我最喜爱的神奇宝贝是'+name)
#需要给参数name赋值,每次调用都可以给参数赋不同的值
pika2('皮卡丘')
pika2('喷火龙')
    
def pika3(name,person):
    print('我最喜爱的神奇宝贝是'+name)
    print('我最喜爱的驯兽师是'+person)
#需要给两个参数分别赋值,并用逗号隔开,否则会报错
pika3('卡比兽','小智')

通过这个例子,我们明白调用函数最关键的是:得弄清楚这个函数有多少个参数,如何给参数赋值,这个过程在函数里叫做参数的传递(pass)。

函数重要概念

主要的参数类型有:位置参数、默认参数、不定长参数。我会用一个案例把这些参数串起来。

假设你最近开了一家深夜食堂,顾客可以任意点菜。但因为人手不足,所以只能为每个人提供一份开胃菜和一份主食。如果写成函数的形式,这个函数就会有两个参数。

def  menu(appetizer,course):
    print('一份开胃菜:'+appetizer)
    print('一份主食:'+course)

menu('话梅花生','牛肉拉面')

这里的’话梅花生’和’牛肉拉面’是对应参数appetizer和course的位置顺序传递的,所以被叫作【位置参数】 ,这也是最常见的参数类型。之前的神奇宝贝函数也有用到:

def pika3(name,person):
    print('我最喜爱的神奇宝贝是'+name)
    print('我最喜爱的驯兽师是'+person)
pika3('卡比兽','小智')

接下来请你观察下面代码不同的调用形式

def  menu(appetizer,course):
    print('一份开胃菜:'+appetizer)
    print('一份主食:'+course+'\n')
#还记得转义字符\n吧,表示换行

menu('牛肉拉面','话梅花生')
menu('话梅花生','牛肉拉面')

#如果采用下面这种形式传递,就不需要理会参数位置
menu(course='牛肉拉面',appetizer='话梅花生')

好,位置参数是怎么一回事,你现在已经差不多明白了吧。

回到这个食堂的故事。经营了一阵子之后,为了吸引更多的人流,你决定给每个顾客免费送上一份甜品绿豆沙,这时候你就可以用到【默认参数】,注意:默认参数必须放在位置参数之后。

def  menu(appetizer,course,dessert='绿豆沙'):
    print('一份开胃菜:'+appetizer)
    print('一份主食:'+course)
    print('一份甜品:'+dessert)

menu('话梅花生','牛肉拉面')
#因为已经默认将'绿豆沙'传递给dessert,调用时无须再传递。

如果一个参数的值是相对固定的,那么设置默认参数就免去了每次都要传递的麻烦。但默认参数并不意味着不能改变,试试运行下列结果。

def menu(appetizer,course,dessert='绿豆沙'):
    print('一份开胃菜:'+appetizer)
    print('一份主食:'+course)
    print('一份甜品:'+dessert)


menu('话梅花生','牛肉拉面')
menu('话梅花生','牛肉拉面','银耳羹')
#银耳羹对应参数dessert

一个萝卜一个坑,因为前两个参数已经有对应的值传递,Python会自动将’银耳羹’传递给参数dessert。

了解完默认参数,我们接着往下看。

后来呢,盛夏来袭,你觉得卖烧烤是个不错的主意。但问题是每个人点的烤串数量都不同,你也不能限定死数量,这时候【不定长参数】就能派上用场,即不确定传递参数的数量。

它的格式比较特殊,是一个星号*加上参数名,来看下面的例子。

def menu(*barbeque):
    print(barbeque)

menu('烤鸡翅','烤茄子','烤玉米')
#这几个值都会传递给参数barbeque

你会发现输出的是这样的结果:(‘烤鸡翅’, ‘烤茄子’, ‘烤玉米’),这种数据类型叫做元组(tuple),我们来复习一下:

元组的写法是把数据放在小括号()中,它的用法和列表用法类似,主要区别在于列表中的元素可以随时修改,但元组中的元素不可更改。

icon
当然我们也可以先生成一个元组,再传入参数。上述代码等价于:

order=('烤鸡翅','烤茄子','烤玉米')
#元组的长度没有限制
def menu(*barbeque):
    print(barbeque)
menu(*order)

和列表一样,元组是可迭代对象,这意味着我们可以用for循环来遍历它,这时候的代码就可以写成:

def menu(appetizer,course,*barbeque,dessert='绿豆沙'):
    print('一份开胃菜:'+appetizer)
    print('一份主菜:'+course)
    print('一份甜品:'+dessert)
    for i in barbeque:
        print('一份烤串:'+i)
        
menu('话梅花生','牛肉拉面','烤鸡翅','烤茄子','烤玉米')

需要注意的是,这时候默认参数也需要放在不定长参数的后面,即dessert=’绿豆沙’要放在*barbeque后面,否则传递的值会对应不上。

return语句

前面我们提到,return是返回值,当你输入参数给函数,函数就会返回一个值给你。事实上每个函数都会有返回值,像我们之前学过的len()函数。

a=[1,2,3]
print(len(a))

当你把参数a放进len() 函数中,它返回来的是3这个数值(列表的长度)。之后,我们就可以调用这个值,比如用print()函数打印出来或干点儿别的。

像常见的type()函数、数据类型转换函数,还有我们之前学过的bool()都是这样,会返回一个值。

而print()函数本身比较特殊,它在屏幕上显示完相关的文本内容就没了,并不会返回一个值给我们。所以,它返回的是空值(None)。

在自定义函数的时候,我们就可以用return语句规定该函数要返回什么值给我们。带return语句的函数是这样的:

def niduoda(age):
    if age < 12:
        return '哈,是祖国的花朵啊'
    elif age < 25:
        return '哇,是小鲜肉呢'
    else:
        return '嗯,人生才刚刚开始'

print(niduoda(30))

参数值30在条件判断中满足else的条件,所以函数返回’嗯,人生才刚刚开始’,再由print()函数打印出来。

提醒一下,函数也是可以互相嵌套的,在这个例子中,niduoda()函数就被嵌套在print()函数里。

可能你会觉得在这个例子中,直接用print不就行了吗,为啥还要用return呢?还有,我们前面讲了那么多函数,好像都是省略了return的啊,比如刚讲的深夜食堂函数和神奇宝贝函数:

#神奇宝贝函数
def pika2(name):
    print('我最喜爱的神奇宝贝是'+name)
pika2('皮卡丘') 
pika2('喷火龙') 

#深夜食堂函数
def menu(appetizer,course,*barbeque,dessert='绿豆沙'):
    print('一份开胃菜:'+appetizer)
    print('一份主菜:'+course)
    print('一份甜品:'+dessert)
    for i in barbeque:
        print('一份烤串:'+i)
        
menu('话梅花生','牛肉拉面','烤鸡翅','烤茄子','烤玉米')

其实是因为在这些例题中,我们的函数功能都是第一时间把参数打印出来。而在很多时候,当多个函数之间相互配合时,我们并不需要第一时间就将结果打印出来,而是需要将某个返回值先放着,等到需要的时候再做进一步的处理。

下面来看个例子:

icon
在我们关于爱情的天真幻想中,我希望我的梦中情人拥有XXX的脸蛋和XXX的身材。

icon
现在需求如下:一、分别定义两个函数,参数为人名,能够返回字符串’XXX的脸蛋’和’XXX的身材’;二、将上述两个函数的返回值拼接在一起之后,再打印出来。请你先思考一下,再点击回车。

相信对你来说并不难,如果一步步地写,代码应该是这样的:

def face(name):
    return name + '的脸蛋'
#该函数返回字符串'XXX的脸蛋'
def body(name):
    return name + '的身材'
#该函数返回字符串'XXX的身材'

face('李若彤') 
body('林志玲')
#分别调用face()和body()函数

print('我的梦中情人:'+face('李若彤') +' + ' + body('林志玲'))
#将返回值拼接并打印出来

前面也讲到,函数可以互相嵌套,所以第7、8行调用face()和body()函数的两行代码可以省略,因为第12行的print()函数中其实已经有调用这两个函数了。

def face(name):
    return name + '的脸蛋'
def body(name):
    return name + '的身材'
print('我的梦中情人:'+face('李若彤') +' + ' + body('林志玲'))

这只是一个非常简单的例子,在类似这种多个函数相互配合的代码中,我们就会非常需要return语句,来帮我们先保留某个函数的返回值,等要用到的时候再调出来用。

但是这样的代码还有个问题,当我想多次调用函数的时候,就需要先复制print那行代码,再分别修改两个函数里的参数。这样的操作既不简洁,也不优雅。就像这样:

def face(name):
    return name + '的脸蛋'
def body(name):
    return name + '的身材'
print('我的梦中情人:'+face('李若彤') +' + ' + body('林志玲'))
#要再次调用就要复制一遍,然后改参数
print('我的梦中情人:'+face('新垣结衣') +' + ' + body('长泽雅美'))

所以更常见的做法是:再定义一个主函数main(),参数调用前两个函数的返回值。先给出代码,你可以琢磨一下,主要思考第5行和第6行代码。

def face(name):
    return name + '的脸蛋'
def body(name):
    return name + '的身材'
def main(dream_face,dream_body):
    return '我的梦中情人:' + face(dream_face) + ' + ' + body(dream_body)

print(main('李若彤','林志玲'))
print(main('新垣结衣','长泽雅美'))

main()函数内部分别调用了face()和body()函数,参数dream_face和dream_body传递给了face()和body()函数的参数name,得到返回值,并打印。看起来有点绕,我们将函数运行的步骤分解,就一目了然了。

!

我们可以总结一下:
需要多次调用函数时,可以再定义一个主函数main(),调用非主函数的返回值。

还是看这段代码:

def face(name):
    return name + '的脸蛋'
def body(name):
    return name + '的身材'
print('我的梦中情人:'+face('李若彤') +' + ' + body('林志玲'))

在这段代码中,我们定义了两个函数,每个return语句分别返回关于“脸蛋”和“身材”的值。如果要一次性返回这两个值,我会这样做,你先看代码:

def lover(name1,name2):
    face = name1 + '的脸蛋'
    body = name2 + '的身材'
    return face,body

a=lover('李若彤','林志玲')
print('我的梦中情人:'+a[0]+' + '+a[1])

为什么要这样写,第7行代码是啥意思?怎么看上去像是列表?你大概有这样的疑惑了吧。

icon
我们先来看看,一次性返回的两个值,是什么数据类型。

#请直接运行代码
def lover(name1,name2):
    face = name1 + '的脸蛋'
    body = name2 + '的身材'
    return face,body

a=lover('李若彤','林志玲')
print(a)

是(‘李若彤的脸蛋’, ‘林志玲的身材’)这样一个元组,对不对?又是元组。

事实上,Python语言中的函数返回值可以是多个,而其他语言都不行,这是Python相比其他语言的简便和灵活之处。一次接受多个返回值的数据类型就是元组。

def lover(name1,name2):
    face = name1 + '的脸蛋'
    body = name2 + '的身材'
    return face,body

a=lover('李若彤','林志玲')
#此时return的值为元组 a = ('李若彤的脸蛋', '林志玲的身材')
print('我的梦中情人:'+a[0]+' + '+a[1])

现在你大概对return的作用有了更深的了解吧。我们继续总结:
python的函数返回值可以是多个,多个返回值的数据类型是元组(tuple)

最后需要再强调的是,没有return语句的函数会默认返回None值。运行下列代码,并观察结果。

#第一个函数
def fun():
    a ='I am coding'
print(fun())

#第二个函数
def fun():
    a='I am coding'
    return a
print(fun())

第一个函数因为没有return语句,返回None值,所以打印出None。

没有return语句的函数会默认返回None值

此外,return还有一个“副作用”:一旦函数内部遇到return语句,就会停止执行并返回结果。你可以运行下列的代码:

def fun():
  return 'I am coding.'
  return 'I am not coding.'

print(fun())

函数内部遇到第一个return就会返回,所以只会打印出’I am coding’。

好啦,关于return语句,我们的知识讲解就到这里。

!

现在呢,趁热打铁,巩固一下学过的知识。

题目是这样的:一、定义一个带有两个参数的函数,函数的功能是返回两个参数中较大的那个值;二、调用函数,将99的平方和8888赋值给参数,并将较大值打印出来。

def big_num(x,y):
    if x>y:
        return x
    elif x==y:
        return '一样大'
    else:
        return y

print(big_num(99**2,8888))