1. 函数的介绍
-
**概述:**函数就是将一段具有独立功能的代码打包在一起的程序结构。当使用该功能时,只需调用该函数即可。
- 函数中的参数:从函数外部向函数内部传递数据,并且参与函数内部代的计算和运行。
- 函数的返回值:将函数内部计算或执行得到的结果传递到函数外部。
- 总结:
- 所有的函数都实现了一个特定的功能。
- 所有的函数都使用
函数名()
进行调用。 - 所有的函数都可以使用变量进行接收(没有返回值的函数接收到的是
None
)。
-
函数的定义:
-
使用关键字
def
定义函数。 -
定义格式:函数名要满足标识符的命名规则,并且见名知意,python中一般使用下划线分割法定义。
def 函数名(): 函数体
-
调用格式:
函数名(参数)
-
-
函数的说明文档:
- 可以在提示信息中展示出来的说明文字,提示信息的出现方式:鼠标悬停在函数调用位置上,或者按住
ctrl
键,鼠标悬停。 - 格式:在函数体的第一行书写多行注释,则为说明文档;如果使用单行注释,将不会进行提示。
- 说明文档可以使用单引号,也可以使用双引号,但是建议使用双引号。
- 可以在提示信息中展示出来的说明文字,提示信息的出现方式:鼠标悬停在函数调用位置上,或者按住
-
函数的作用:
- 提高代码的复用率,通过将一段常用的代码封装成函数,我们可以在需要的时候多次调用该函数,从而减少代码量,提高开发效率和代码的可读性。
-
注意:
- 定义函数时,必须先定义后调用。如果在函数定义之前调用函数,会引发
NameError
异常。 - 如果出现同名函数,后定义的函数会覆盖先定义的函数。
- 如果出现同名的变量,变量会覆盖函数的定义。
- 在执行代码时,不会执行函数中的代码,仅记录函数的名称,只有当函数被调用时,才会执行函数的代码。
- 定义函数时,必须先定义后调用。如果在函数定义之前调用函数,会引发
-
代码示例:
# 定义函数 def func(): print('hello') print('world') print('bye') # 函数的调用 func() # print_start() # NameError: name 'print_start' is not defined def print_start(): for i in range(5): for j in range(5): print('*', end=' ') print() print_start() # 如果使用单行注释,则不能在鼠标悬停的时候进行提示 def func2(): # 打印一首诗 print('仰天大笑出门去,我辈岂是蓬蒿人。') func2() # 如果在函数体第一行使用多行注释,则可以在鼠标悬停的时候进行提示 def func3(): '''打印一首诗''' print('仙人抚我顶,结发受长生。') func3() # 如果在函数体第一行使用多行注释,则可以在鼠标悬停的时候进行提示 def func4(): """打印一首诗""" print('沾衣欲湿杏花雨,吹面不寒杨柳风。') func4()
2. 函数的参数
-
**概述:**函数的参数就是在调用函数的位置向函数内传递数据,并参与函数内部的运算或执行,通过传递参数的不同可以改变函数的执行结果。
-
**作用:**让代码更加灵活,让函数的复用率更高,提高开发效率。
-
格式:
def 函数名(参数1, 参数2, 参数3 ...)
-
分类:
- 形参:函数定义位置的参数,只是形式上参与了运算,实际上是一个变量名,所以称为形参。
- 实参:在函数调用位置的参数,是传递到函数体内部真正参与运算的数据,所有称为实参。
-
参数传递:
- 实参—位置参数:
- 实参中位置参数的赋值方式就是从左到右依次赋值,不能多也不能少。
- 位置参数无法跳跃赋值,也无法指定赋值位置,只能从左至右按序赋值。
- 实参—关键字参数:
- 关键字参数赋值,就是根据形参的名称对指定的形参进行赋值。
- 格式:
形参名 = 值
- 使用关键字赋值,不能重复赋值,也不能遗漏赋值。
- 使用的形参名必须存在。
- 位置参数赋值和关键字参数赋值可以同时使用,此时位置参数仍旧是从左到右依次赋值。
- 形参—位置参数:
- 形参中的位置参数从左到右依次定义,这种参数必须赋值,否则会引发
TypeError
异常。
- 形参中的位置参数从左到右依次定义,这种参数必须赋值,否则会引发
- 形参—缺省参数:
- 可以理解为给参数一个默认值,如果调用的时候不赋值,就使用默认值,否则就使用新赋的值。
- 缺省参数在定义时,只能放在位置参数之后,否则会引发
SyntaxError
异常。 - 缺省参数中设置的默认值一般是不需要修改的,如果每次调用都需要修改就没必要使用缺省参数。
- 形参—位置不定长参数:
- 可以接收任意多个位置参数的参数类型,是形参的一种,在函数定义时使用。
- 格式:在函数的参数列表中使用
*args
。 - 传入多个实参,会打包为一个元素,保存在
args
中。 *args
不能使用关键字参数进行赋值。*args
可以和其他参数类型一起使用,但是如果位置参数在*args
之后,将只能以关键字赋值的形式修改值的内容。- 推荐的参数顺序:位置参数>位置不定长参数>缺省参数(此时只能通过关键字方式修改缺省参数)
- 形参—关键字不定长参数:
- 接收任意多个关键字参数的形参类型。
- 格式:
**kwargs
- 在实参中,使用关键字不定长参数赋值,会将其以字典的形式打包写入
kwargs
中。 kwargs
不能通过关键字参数赋值。kwargs
可以和其他形参类型一起使用,但是只能放在末尾。
- 实参—位置参数:
-
代码示例:
# 定义一个函数,接收四个位置参数 def func1(a, b, c, d): print(a, b, c, d) # 位置参数赋值 func1(1, 2, 3, 4) # func1(1, 2, 3) # TypeError: func1() missing 1 required positional argument: 'd' # func1(1, 2, 3, 4, 5) # TypeError: func1() takes 4 positional arguments but 5 were given # 关键字参数赋值 func1(a=1, b=2, c=3, d=4) func1(b=1, c=2, a=3, d=4) func1(1, 2, c=3, d=4) # func1(1, 2, a=3, b=4) # TypeError: func1() got multiple values for argument 'a' # func1(b=1, c=2, a=3) # TypeError: func1() missing 1 required positional argument: 'd' # func1(a=1, b=2, c=3, f=4) # TypeError: func1() got an unexpected keyword argument 'f' # 形参——缺省参数 def func2(a, b, c=9): print(a, b, c) func2(1, 2, 3) # 1 2 3 func2(1, 2) # 1 2 9 # SyntaxError: parameter without a default follows parameter with a default # def func3(a=10, b, c): # print(a, b, c) # 不定长位置参数 def func3(*args): print(args) func3(1, 2, 3) # (1, 2, 3) # func3(*arg=(1, 2, 3)) # SyntaxError: cannot assign to iterable argument unpacking # 位置不定长参数和其他参数类型一起使用 def func4(a, *args, b=10): print(a, args, b) func4(1, 2, 3, 4) # 1 (2, 3, 4) 10 func4(1, 2, 3, 4, b=20) # 1 (2, 3, 4) 20 # 关键字不定长参数 def func5(**kwargs): print(kwargs) func5(name='Alice', age=20) # {'name': 'Alice', 'age': 20} # 多种参数类型混合使用 def func6(a, b, *args, c=10, **kwargs): print(a, b, args, c, kwargs) func6(1, 2, 3, 4, c=20, name='Bob', age=30) # 1 2 (3, 4) 20 {'name': 'Bob', 'age': 30}
3. 函数的返回值
-
**概述:**就是函数体内部运算或执行的结果,要传递到函数外部进行使用,就必须使用返回值进行传递。
-
**格式:**使用
return
关键字,将函数运行的结果传递到函数外部。 -
注意:
- 一般使用函数返回值时,都会使用变量进行接收。
return
的作用是返回数据,并且结束函数的运行,所以一个函数只有第一个return
被执行。- 使用
return
返回数据时,如果写值则返回该值,如果不写返回值或者不写return
则返回None
。 - 返回值有且只有一个,如果想要返回多个值,可以使用容器类型(如列表、元组、字典等)打包后进行返回。
- 如果返回多个数据,使用逗号隔开,会自动打包成一个元组进行返回。
-
代码示例:
# return def func1(): print('hello world') return 'hello world' return 'python' print('hello python') print(func1()) # return 'hello world',之后的代码不会被执行 def func2(): print('hello c') return print(func2()) # None def func3(): print('hello cpp') print(func3()) # None # 返回多个值 def func4(): return 1, 2, 3 result = func4() print(result) # (1, 2, 3) # 接收多个返回值 a, b, c = func4() print(a, b, c) # 1 2 3
4. 变量的作用域
-
**概述:**变量的生效范围称为变量的作用域。在python中,变量的作用域主要分为全局作用域和局部作用域。
-
分类:
- 全局变量:在文件中顶格书写,从定义位置开始,在函数内和函数外都可以使用的变量。
- 局部变量:在函数体内定义,只能在定义的函数体内使用的变量。
-
**
global
关键字:**将变量声明为全局变量,实现在函数体内修改全局变量的值,必须先声明后使用。 -
注意:
- 无论是全局变量还是局部变量,都必须遵循先定义后调用的原则。
- 在函数体内,优先调用局部变量,如果没有局部变量才会去全局变量中找。
- 局部变量和全局变量即便名称相同也不是同一个变量,在同一个函数体内要么使用全局变量,要么使用局部变量。
global
关键字声明后,函数体内使用的都是全局变量。
-
代码示例:
# 全局变量 name = '李白' def func1(): print(f'他的名字叫:{name}') func1() print(f'他的名字叫:{name}') def func2(): age = 18 print(f'他今年 {age} 岁') func2() # print(f'他今年 {age} 岁') # NameError: name 'age' is not defined num1 = 1 def func1(): num1 = 100 print(num1) # 100 func1() print(num1) # 1 def func2(): global num1 num1 = 100 print(num1) func2() print(num1) # 100
5. 组包和拆包
-
**组包:**将多个数据自动合并为一个数据的过程。在python中,当我们返回多个值时,python会自动将这些值打包成一个元组。
-
**拆包:**将一个数据自动拆分为多个数据的过程。
- 集合类型数据拆包后顺序不一定。
- 字典类型数据拆包后获取的是字典的键。
-
代码示例:
# 组包 def func1(): return 1, 2, 3, 4 a = func1() print(a) # (1,2,3,4) # 拆包 num1, num2 = (1, 2) print(num1, num2) v1, v2 = 1, 2 print(v1, v2) # 1 2 v1, v2 = v2, v1 print(v1, v2) # 2 1 # 字典拆包 dict1 = {'name': 'Alice', 'age': 20} key1, key2 = dict1 print(key1, key2) # name age
6. 匿名函数
-
**概述:**匿名函数又叫
lambda
表达式,是函数的另一种定义方式。与def
定义的普通函数不同,匿名函数没有函数名,但是在调用时,使用方式与普通函数完全一致。 -
格式:
lambda 参数列表: 返回值
-
**作用:**匿名函数的最大作用就是可以将函数更加方便的以参数的形式传递到函数体内部。
-
代码省示例:
# def 定义普通函数 def sum1(num1, num2): return num1 + num2 print(sum1(3, 4)) # 7 # lambda 表达式定义匿名函数 # 定义 lambda num1, num2: num1 + num2 # 调用 # 方式一:直接调用 # 此方法不需要函数名,但是这种方法定义的匿名函数只能调用一次,下次使用需要重新定义。 res = (lambda num1, num2: num1 + num2)(3, 4) # 7 print(res) # 方式二:间接调用(使用变量接收匿名函数后再使用()进行调用) sum2 = lambda num1, num2: num1 + num2 print(sum2(3, 4)) # 7 # 使用方式二定义的匿名函数,可以多次使用 print(sum2(4, 5)) # 9 # 匿名函数的最大作用就是可以将函数更加方便的以参数的形式传递到函数体内部 # sort 函数 (列表排序函数) list1 = [1, 2, 6, 7, 5, 4, 3] list1.sort() print(list1) # [1, 2, 3, 4, 5, 6, 7] # sort的完整格式 列表.sort(self, key, reverse) # self:不需要传值,系统自动传值 # key:排序规则,需要传递一个函数,一般我们习惯使用匿名函数 # reverse:升序降序,默认为False 是升序,如果修改为True 是降序 # sort函数中的key参数需要传递一个函数定义 list2 = [(3, 4), (2, 1), (5, 3), (6, 2)] # 需求:自定义规则进行排序,让list2中的元素,按照元组中的第二个元素的大小进行排序 # 举例:(3,4) > (5,3) 因为 4 大于 3 # 此时就需要使用到参数key:列表.sort(key = lambda 元素 : 排序规则) list2.sort(key=lambda x: x[1]) # sort(key=lambda x: x[1]) # 解释: 遍历列表,每次将一个元素进行传入,用x接收,我们返回的排序规则是x[1],也就是按照元组元素的下标为1的元素排列大小 print(list2) # [(2, 1), (6, 2), (5, 3), (3, 4)]
7. 递归
-
**概述:**就是在函数内部调用函数本身的计算方法。递归函数通常用于解决可以分解为相同子问题的问题。
-
注意:
- 函数定义的内部必须调用函数本身。
- 要有明确的函数跳出条件,否则会导致无限递归,最终引发
RecursionError
异常。 - 不能超出最大调用深度,Python 对递归调用的深度有一定的限制。
- 递归效率极低,因为递归会重复计算很多相同的子问题,导致时间复杂度较高。
-
代码示例:
# 递归 def fibonacci(n): if 0 < n <= 2: # 递归出口 return 1 return fibonacci(n - 1) + fibonacci(n - 2) # 调用函数本身 print(fibonacci(5))