python小白学习笔记《8.函数》
0.初识函数
0.0函数的作用
前面学习过的循环是减少代码重复的一种手段,那么接下来要学习的函数则是Python里增强代码重用性最有力的工具,它的定义是:
函数是组织好的、可以重复使用的、用来实现单一功能的代码。
什么意思呢?我们之前所写的代码都是立即运行且只能被执行一次,而函数可以让我们整合打包好代码,以便这些代码能够随时被复用,这样能极大地减少代码冗余。
往后,随着我们想要实现的功能越来越复杂,代码可能会有几百上千行,这样对写代码和读代码都是一个挑战。如果将一个程序用函数拆分成多个独立的子任务来完成,就会让代码结构变得清晰许多。
0.1函数的组成
函数(Function)能实现的功能从简单到复杂,各式各样,但其本质是相通的,我们可以看作成三个部分。
在Python中,函数也是如此,“喂”给函数一些数据,它就能内部消化,执行相应的功能,最终给你“吐”出你想要的东西,就好比自动贩卖机一样。
Python本身就自带的一些函数,也叫内置函数,提供了许多我们常用的基本功能。像print(), input(), len(), str(), int(), float()等等。
括号里放的东西,也就是我们需要输入给函数的数据,它在函数中被称作【参数】。【参数】指向的是函数要接收、处理怎样的数据(你也可以把它理解成自变量)。
除了Python自带的内置函数,我们还能根据自己的需要,自己定义一个独一无二的函数~
0.2定义和调用函数
编写函数的第一步,我们需要去定义一个函数,我们先来看看基本语法:
def 函数名(参数):
函数体
return 语句
照着这个语法,我们以y = 2x + 3为例子,来定义一个一次函数。
def math(x):
y = 2*x + 3
return y
第1行:def的意思是定义(define),math是【函数名】(自己取的),再搭配一个英文括号和冒号,括号里面的x是参数(参数名也是自己取)。
第2行:def下一行开始缩进的代码就是函数要实现的功能,也叫【函数体】。这里的功能就是:根据x计算出一个值y。
第3行:return语句是返回的意思,可以指定函数执行完毕后最终会返回什么值或表达式,否则计算机是无法判断出函数最终要输出什么结果的。
定义函数的语法并不难,但有些注意事项一开始要特别注意才能少踩坑:
一、函数名:
- 名字最好能体现函数的功能,一般用小写字母和单下划线、数字等组合
- 不可与内置函数重名(内置函数不需要定义即可直接使用)
二、参数:
根据函数功能,括号里可以有多个参数,也可以不带参数,命名规则与函数名相同
三、规范:
括号是英文括号,后面的冒号不能丢
四、函数体:
函数的执行过程,体现函数功能的语句,要缩进,一般是四个空格
五、return语句:
后面可以接多种数据类型,如果函数不需要返回值的话,可以省略
那么该怎么调用函数呢,让它发挥作用呢?很简单,就是输入函数名和参数所对应的值,这个过程在函数里叫作参数的传递(pass)。
def math(x):
y = 2*x + 3
return y
a = math(5)
print(a)
#终端13
小操作:
写出一个能计算字符串长度的函数,然后传递参数’小白在学习’来调用函数,并将结果打印出来。
思路:
- 设置一个初始为0的计数器;
- 遍历字符串,每遍历一次,计数器加一;
- 返回计数器的值。
def my_len(words):
counter = 0
for i in words:
counter += 1
return counter
a = '小白在学习'
print(my_len(a))
#等价于print(my_len('小白在学习'))
#终端:5
1.函数的进阶使用
1.0参数类型
def my_goal():
print('学会python')
print('学会理财')
print('赚大钱')
my_goal()
终端:
这里定义了一个my_goal()函数,但是括号里没有带参数,原因是这个函数的功能是打印出固定的三句话,不需要参数的参与。
即便是没有参数,我们在调用函数的时候也不能省略括号,如此例中的my_goal()。
i在这个例子里,也不需要return语句,原因是这个函数直接在屏幕打印出内容,不需要返回值。
事实上,没有return语句的函数,Python也会在末尾隐性地加上return None,即返回None值。
换句话说,有时候我们需要的只是函数的执行过程(比如打印内容),有时我们需要函数执行完毕的返回结果。
那接下来,我们来看看有多个参数的情况。
def time_table(morning,noon,afternoon):
print('8:00-10:00'+ morning)
print('10:30-12:00'+ noon)
print('14:00-16:00'+ afternoon)
time_table('学英语','健身','学Python')
终端:
这里的’学英语’、'健身’和’学Python’是对应参数的位置顺序传递的,所以morning,noon,afternoon被叫作【位置参数】,当有多个参数的时候,我们就必须按照顺序和数量传递,这也是最常见的参数类型。
除了【位置参数】,还有【默认参数】,直接在定义函数的时候给参数赋值。
def time_table(morning,noon,afternoon,evening = '画画'):
print('8:00-10:00'+ morning)
print('10:30-12:00'+ noon)
print('14:00-16:00'+ afternoon)
print('20:00-22:00'+ evening)
time_table('学英语','健身','学Python')
#因为已经默认将'画画'传递给evening,调用时无须再传递。
终端:
需要注意的是:默认参数必须放在位置参数之后。
如果一个函数的某个参数值总是固定的,那么设置默认参数就免去了每次都要传递的麻烦。
不过默认参数并不意味着不能改变:
def time_table(morning,noon,afternoon,evening = '画画'):
print('8:00-10:00'+ morning)
print('10:30-12:00'+ noon)
print('14:00-16:00'+ afternoon)
print('20:00-22:00'+ evening)
time_table('学英语','健身','学Python','刷抖音')
终端:
因为前三个位置参数已经有对应的值传递,Python会自动将’刷抖音’传递给参数evening,替换了默认参数的默认值。
【不定长参数】传递给参数的数量是可选的、不确定的。
它的格式比较特殊,是一个星号*加上参数名,它的返回值也比较特殊,我们来看看下面的例子:
def BP(*BlackPink):
for i in BlackPink:
print('绝世美人:' + i)
BP('Jisoo','Jennie','Rose','Lisa')
# 不定长参数可以接收任意数量的值
终端:
1.1返回多个值
函数不仅可以支持输入多个参数,而且也可以同时输出多个值。
import random
BP = ['Jisoo','Jennie','Rose','Lisa']
def choose(num):
if num == 1:
a = random.choice(BP)
return a
elif 1 < num <= 4:
b = random.choice (BP)
return b, '别想那么多'
result = choose(2)
print(result)
终端:
2.多个函数间的配合
2.0变量作用域
函数用来封装独立的功能,所以一个程序往往是通过多个函数的配合来实现的。
当多个函数同时运行时,就涉及函数中一个非常重要的概念 —— 变量作用域。
什么是变量作用域呢?我们还是先来看看一个例子。
月底了,身为老板的你要核算成本来调整经营策略,假设餐馆的成本是由固定成本(租金)和变动成本(水电费 + 食材成本)构成的。
那么我们可以分别编写一个计算变动成本的函数和一个计算总成本的函数,请阅读下列代码:
rent = 3000
def cost():
utilities = int(input('请输入本月的水电费用'))
food_cost = int(input('请输入本月的食材费用'))
variable_cost = utilities + food_cost
print('本月的变动成本费用是' + str(variable_cost))
def sum_cost():
sum = rent + variable_cost
print('本月的总成本是' + str(sum))
cost()
sum_cost()
乍一看代码好像没有什么问题,但是一旦运行,终端就会报错。
sum = rent + variable_cost
NameError: name ‘variable_cost’ is not defined
可以发现第一个函数cost()运行没有问题,报错信息指出问题出在第10行,sum_cost()函数内的变量variable_cost没有被定义。
这就涉及一个变量作用域的问题:程序中的变量并不是在哪个位置都可以被使用的,使用权限决定于这个变量是在哪里赋值的。关于这个概念,目前我们只需要掌握下面两点即可:
第一点:一个在函数内部赋值的变量仅能在该函数内部使用(局部作用域),它们被称作【局部变量】,如cost()函数里的variable_cost。
第二点:在所有函数之外赋值的变量,可以在程序的任何位置使用(全局作用域),它们被称作【全局变量】,如第一行的rent。
在这个例子中,变量rent是在函数外被赋值的,所以它是全局变量,能被sum_cost()函数直接使用。
而变量variable_cost是在cost()函数内定义的,属于局部变量,其余函数内部如sum_cost()无法访问。事实上,当cost()函数执行完毕,在这个函数内定义的变量都会"消失”。
那要怎么解决“局部变量”和”全局变量“之间的矛盾呢?有几种方法可供参考,第一种方法最取巧:把局部变量都放在函数外,变成全局变量。还是以上面的代码为例:
rent = 3000
utilities = int(input('请输入本月的水电费用'))
food_cost = int(input('请输入本月的食材费用'))
variable_cost = utilities + food_cost
# 以上均为全局变量
print('本月的变动成本是' + str(variable_cost))
def sum_cost():
sum = rent + variable_cost
print('本月的总成本是' + str(sum))
sum_cost()
那有没有一个能在函数内修改的方法呢?这时候global语句就能派上用场了,它可以将局部变量声明为全局变量,仔细看第四行代码。
rent = 3000
def cost():
global variable_cost
utilities = int(input('请输入本月的水电费用'))
food_cost = int(input('请输入本月的食材费用'))
variable_cost = utilities + food_cost
print('本月的变动成本是' + str(variable_cost))
def sum_cost():
sum = rent + variable_cost
print('本月的总成本是' + str(sum))
cost()
sum_cost()
global语句一般写在函数体的第一行,它会告诉Python,“我希望variable_cost是个全局变量,所以请不要用这个名字创建一个局部变量”。所以sum_cost()函数内部现在可以直接使用声明后的全局变量variable_cost。
2.1函数的嵌套
在一个函数内部调用其他函数,那么刚刚的例子就可以写成:
rent = 3000
def cost():
utilities = int(input('请输入本月的水电费用'))
food_cost = int(input('请输入本月的食材费用'))
variable_cost = utilities + food_cost
print('本月的变动成本是' + str(variable_cost))
return variable_cost
def sum_cost():
sum = rent + cost()
print('本月的总成本是' + str(sum))
sum_cost()
cost()函数运行结束后会返回变量variable_cost,而sum_cost()函数内部调用了cost(),所以调用sum_cost()的时候,cost()函数也会执行,并得到返回值variable_cost。
sum = rent + cost() 的结果就是sum = rent + variable_cost。最后调用函数时,也只需调用sum_cost()即可。
阅读下面三个函数,弄明白当调用main()主函数的时候,程序是怎么运行的:
def div(num1, num2):
growth = (num1 - num2) / num2
percent = str(growth * 100) + '%'
return percent
def warning():
print('Error: 你确定上个月一毛钱都不赚不亏吗?')
def main():
while True:
num1 = float(input('请输入本月所获利润'))
num2 = float(input('请输入上月所获利润'))
if num2 == 0:
warning()
else:
print('本月的利润增长率:' + div(num1,num2))
break
main()
可以看到,div()函数会计算并返回利润率,warning()函数是打印出一句提示,它们都被嵌套在main()主函数里,当满足不同的条件时,这两个子函数会被调用。
所以虽然定义了三个函数,但最后只需调用main()函数即可。
结合注释来看下这段代码的执行顺序:(按箭头所标的序号)