内容概要:
- 函数的简介
- 函数的参数
- 变量的作用域
- 递归函数
一.函数
1.什么是函数?
函数就是执行特定任务和以完成特定功能的一段代码.
生动形象一点:
函数就是这个榨汁机,草莓是参数,我们将草莓(参数)放进榨汁机(函数)里,榨汁机(函数)实现它的功能,得到草莓汁(返回结果)
2.为什么需要函数:
- 复用代码
- 隐藏实现细节
- 提高可维护性
- 提高可读性, 便于调试
3.函数的创建
如果一个函数没有返回值,末尾也自动有return,那到底返回了什么呢? None ->空对象 (空值) python中不能对none对象进行任何操作
return关键字可以在函数中的任意位置出现,一旦函数执行到return关键字,函数就会立即结束
4.main函数与自定义函数
1.在每个 Python 文件的定义中都包括一个顶级模块的__name__变量的值为 main. 概述 : python 程序模块的入口就是 main 函数. main 函数是程序执行的入口,同时也是出口
2.如果代码没有写在自定义函数中,那么这些代码就相当于写在了主函数中
if __name__ == '__main__': #表明主函数,主函数内容要缩进
5.内存中的栈区(stack)在执行函数时的特点:先进后出
进去:入栈(push)
出去:弹栈(pop)
函数在执行时main函数先入栈,调用函数时,定义的函数在入栈,执行完毕即出栈,能够节省内存空间,待到main函数执行结束后全部出栈,栈区为空,程序结束
二.函数的参数
1.位置参数:
位置参数,有时也称必备参数,指的是必须按照正确的顺序将实际参数传到函数中,换句话说,调用函数时传入实际参数的数量和位置都必须和定义函数时保持一致。
来看第一个案例:
需求:定义一个功能实现多个整型数值的累加和
#需求是定义一个功能实现多个整型数值的累加和
def get_sum(.....)
#写到这里就有点迷糊了,'多个'整型数值,参数的个数是未知
解决办法:
#需求:定义一个功能实现多个整型数值的累加和
#定义一个函数
def get_sum(*args):
# *args为位置参数,可以传递多个数值,并且会将输入的参数包装为一个元组
count = 0
for num in args: # args就是我输入的参数(arguments->形式参数)
count += num
return count
#调用函数
sum = get_sum(11, 23, 13, 45)
print(sum)
那么如果我输入的是一个列表类型的数据呢?
def get_sum(*args):
count = 0
for i in args:
count += i
return count
num_list = [10, 20, 30]
sum = get_sum(num_list)
print(sum)
#TypeError: unsupported operand type(s) for +=: 'int' and 'list'
发生错误
解决办法:
def get_sum(*args):
count = 0
for i in args:
count += i
return count
num_list = [10, 20, 30]
sum = get_sum(*num_list)
#在num_list前面加一个*,会将列表中的元素一一取出,再包装为一个元组
print(sum)
那么如果我输入的也是一个元组数据呢???(逐渐离谱)
def get_sum(*args):
count = 0
for i in args:
count += i
return count
num_tuple = (10, 20, 30)
sum = get_sum(*num_tuple)
# 也需要使用*将元组先拆解出其各个元素再通过*args包装为一个元组数据->args
print(sum)
2.关键字参数:
def math_function(a, b, c):
sum = a + b - c
return sum
sum = math_function(3, 2, 1)
#引用函数时如果输入的参数没有表明关键字,则按照位置参数原则:传入的参数与定义的数据位置数量相同
#################################################################################
def math_function(a, b, c)
sum = a +b - c
return sum
sum = math_function(a = 3, c = 2, b = 6) #表明了关键字则按照关键字来
print(sum)
那么如果我输入的参数是以字典的形式呢??
例如:
def math_function(a, b, c):
sum = a + b - c
return sum
num_dict = {'a': 30, 'b':10, 'c':20}
sum = math_function(num_dict)
print(sum)
运行发现:
TypeError: math_function() missing 2 required positional arguments: ‘b’ and ‘c’
类型错误:math_function()函数缺少了两个必需的位置参数b和c
说明传入de字典参数是一个整体,只代表了一个位置参数 ‘a’
解决办法:
def math_function(a, b, c):
sum = a + b - c
return sum
num_dict = {'a': 30, 'b':10, 'c':20}
sum = math_function(**num_dict) #在这里加两个**,可以先将字典拆分为关键字参数实现传递
print(sum)
说明:字典数据实现关键字传参,需要添加两颗星星
3.有多种类型的参数的函数
# args为位置参数,*args能传递多个参数;**kwargs为关键字参数
def math_function(n1, n2, n3, *args, **kwargs): # **kwargs能将参数包装为字典
print(n1)
print(n2)
print(n3)
print(args)
print(kwargs)
math_function(10, 20, 30, 40, 50, 60, a = 33, b = 44, c = 55)
如果这样子的话:
def math_function(*args, n1, n2, n3, **kwargs): # **kwargs能将参数包装为字典
print(n1)
print(n2)
print(n3)
print(args)
print(kwargs)
math_function(10, 20, 30, 40, 50, 60, a = 33, b = 44, c = 55)
*args会将所有的位置参数打包,那么n1,n2,n3这仨关键字参数就g了
再或者这个样子:
def math_function( n1, n2, n3, **kwargs, *args): # **kwargs能将参数包装为字典
print(n1)
print(n2)
print(n3)
print(args)
print(kwargs)
math_function(10, 20, 30, 40, 50, 60, a = 33, b = 44, c = 55)
程序会报错
4.参数的默认值
函数的参数可以设置默认值,有默认值的参数在调用函数时可以不传递,直接使用默认值
def get_sum(a, b = 10): #只能这样写而不能写(b = 10, a) 有默认值的参数必须在无默认值参数的后面
sum = a + b
return sum
sum = get_sum(30) #这里只写一个参数a,b默认为10
三.变量的作用范围/作用域
1.局部变量
def math_function():
n = 100 #在函数内定义一个变量
print(f'n = {n}')
#调用函数
math_function
#运行正常的到n = 100
#但如果没有运行这个函数直接输出
print(n)
#NameError: name 'n' is not defined
#显示n是未被定义的说明n只在函数内起作用
这种只能在自定义函数中起作用的变量被称为局部变量
2.全局变量
主函数中定义的变量被称为’全局变量’
全局变量可以在所有自定义函数中使用,但使用时要声明该变量为全局变量:
#一定要先定义变量再声明使用,否则会出现语法错误
n = 924
def num_function():
global n #声明后就可以在自定义函数中使用了
print(n)
num_function() #调用函数 不要漏掉括号(~ ̄▽ ̄)~
四.递归函数
1.递归:自己调用自己
举个例子:
def say_hi():
print('这是雪豹')
say_hi()
if __name__ == '__main__':
say_hi()
代码解析:
#首先定义了一个函数,函数的功能是输出'这是雪豹'
def say_hi():
print('这是雪豹')
say_hi() #执行过后再次调用本身,再次执行该功能一直循环-->'死递归'
同时发现报错:
RecursionError: maximum recursion depth exceeded while calling a Python object
递归错误:在调用python对象的时候达到递归对象的最大深度
因此不能使用’死递归’
因此,递归使用时的注意点:
一定要考虑清楚如何结束这个死递归 – >添加递归结束的条件
2.递归的优缺点:
- 优点:代码和思路简单
- 缺点:没递归调用一次函数都会在栈内存分配一个栈,占用内存多效率低下
久违了😭,前段时间开学,忙着和舍友团建mc