函数的价值:
1)将代码块分块
2)将重复性功能进行封装以简化程序
1)概念:函数就是对实现某一特定功能的代码的封装 - 机器
函数的本质就是一段代码(包在函数内的那些代码)
2)函数的分类
系统函数(系统造好的机器) - 由python创建好的函数,例如:print、input、type、max、min、id等
自定义函数 - 由程序员自己创建的函数
2.定义函数(创建函数)语法:
def 函数名(形参列表):
函数说明文档
函数体
说明:
a. def - 关键字:固定写法
b. 函数名 - 由程序员自己命名
要求:是标识符;不能是关键字
规范:见名知义(看到函数名大概知道该函数的功能是什么);
所有字母都小写,多个单词之间用下划线隔开;
不使用系统的函数名、类名和模块名。
c. () - 固定写法
d. 形参列表 - 以’变量名1, 变量名2, 变量名3, …'格式存在。
这儿的每一个变量就是一个形参,如果不需要形参,括号里什么都不写,但括号必须写
形参是用来将函数外部的数据传递到函数内部。(可以理解成连接函数外部和内部的通道(只进不出))
是否需要形参:看实现函数的功能需不需要额外的数据
e. : - 固定写法
f. 函数说明文档 - 本质就是文档注释
相当于机器的说明书;
可有可无
g. 函数体 - 和def保持一个缩进的一条或多条语句;
函数体就是实现函数功能的代码
# 练习1:定义一个函数,求两个数的和
def sum2(num1, num2):
'''获得两个数的和'''
print(num1 + num2)
# 练习2:定义一个函数,求N的阶乘
# N! = 1*2*3*...*N
def factorical(n):
'''求取一个数的阶乘'''
result = 1
for x in range(1, n + 1):
result *= x
print(result)
3. 定义函数的基本流程
初学者定义函数的基本流程:
第一步:确定函数功能
第二步:根据函数功能确定函数名
第三步:确定形参(看实现函数的功能需不需要额外的数据,需要几个)
第四步:实现函数功能(将形参当成对应的数据来使用)
第五步:确定函数返回值
第六步:写函数说明文档
2. 调用函数调用函数(使用机器)
- 定义函数的时候不会执行函数体,调用函数的时候才会执行函数体(重要!)
即使函数体内的代码有错也不会报错
-
调用函数
语法:函数名(实参列表)
说明:
a. 函数名 - 需要使用的函数的名字。(函数名必须是已经定义过的函数的函数名)
b. () - 固定写法
c. 实参列表 - 多个数据用逗号隔开:数据1,数据2,数据3,…
原则上定义函数的时候有多少个形参,调用函数需要多少个实参 -
函数调用过程
当代码执行到函数调用表达式的时候:
第一步:回到函数定义的位置,用实参给形参赋值(传参)
第二步:执行函数体
第三步:确定函数返回值
第四部:回到函数调用的位置,接着往后执行
# 1)调用函数会执行函数体,调用多少次就执行多少次
def func1():
print('=======')
func1()
func1()
# 2) 原则上实参的数量应该与形参数量相同
def func1():
pass
# func1(10) # 报错(不需要实参):TypeError: func1() takes 0 positional arguments but 1 was given
def func2(x):
pass
# func2() # 报错(未给实参):TypeError: func2() missing 1 required positional argument: 'x'
# func2(10,20) # 报错(多给了实参): TypeError: func2() takes 1 positional argument but 2 were given
# 3)每个实参可以是任何有结果的表达式(不能为赋值语句(赋值语句是没有结果的))
def func3(x):
pass
func3(200 - 100)
str1 = 'abc'
func3(str1[1])
func3(str1.upper())
func3(str1.upper() + '123')
3. 返回值
返回值 - 将函数内部的数据传递到函数外部
打印 - 只是程序调试的手段,并不是返回值
-
怎样将一个数据作为函数的返回值
语法:
return 需要返回的数据(需要从函数内部传递到函数外部的数据);多个数据之间用逗号隔开注意:若函数体内未写return,仍然有返回值,返回值为None
-
怎样在函数外部获取函数的返回值
获取函数调用表达式的值就是获取函数的返回值。(函数调用表达式的值就是函数的返回值)
返回值能做的事,函数调用表达式都可以做
def my_sum(num1, num2):
return num1 + num2
sum1 = my_sum(10, 20)
print(sum1)
print(my_sum(10,20))
# 练习:执行以下代码后控制台的打印结果是?
def func(x, y):
x.append(y*2)
return x
list1 = [func([10, 20], 30), 'abc']
# [[10, 20, 60],'abc']
print(list1[0][-1]) # 60
4. return关键字
return的作用有两个:
- 确定函数返回值(将函数内部的数据传递到函数外部)
- 提前结束函数(在执行函数体的时候,如果遇到了return,那么函数直接结束)
def func1():
print('----')
return 10
print('++++')
print('====')
func1() # ----
# 但仍然返回了10,只是没有对返回值10进行接收
print(func1()) # -----
# 10
def download(state):
if not state:
return
print('连接服务器,下载数据')
download(True) # 连接服务器,下载数据
download(False) # (啥都没有)
def odevity(num):
if num % 2:
return '奇数'
return '偶数'
# 若为奇数,遇到语句“return '奇数'”,此时函数功能提前结束,不会再执行“return '偶数'”
5. 函数参数
5.1 位置参数和关键字参数
- 位置参数 - 直接将多个数据用逗号隔开,让实参和形参从位置上一一对应(第一个实参给第一形参赋值,第二个实参给第二个形参赋值)
- 关键字参数 - 以’形参’='实参’的形式传参
- 位置参数和关键字参数混用 - 位置参数必须在关键字参数前面
def func1(x, y, z):
print(f'x:{x},y:{y},z:{z}')
# 位置参数
func1(10, 20, 30) # x:10,y:20,z:30
# 关键字参数
func1(x=10, y=20, z=30) # x:10,y:20,z:30
func1(x=10, z=30, y=20) # x:10,y:20,z:30
# 位置参数和关键字参数混用
func1(10, 20, z=30)
func1(10, z=30, y=20)
# func1(x=10, 20, 30) # 报错,位置参数应在关键字参数前面。SyntaxError: positional argument follows keyword argument
result = sorted([23, 46, 53, 32], reverse=True)
5.2 参数默认值
定义函数的时候可以通过’形参 = 数据’给参数赋默认值,调用函数的时候有默认值的参数可以不用传参。
定义函数的时候可以只给部分参数赋默认值,那么这个时候没有默认值的参数必须在有默认值参数的前面。
def func2(x, y=20, z=30):
print(f'x:{x},y:{y},z:{z}')
func2(10) # x:10,y:20,z:30;x无默认值,必须传参
func2(100) # x:100,y:20,z:30
func2(100, 200) # x:100,y:200,z:30
func2(10, y=200) # x:10,y:200,z:30
5.3 参数类型说明和返回值类型说明
参数类型说明:
-
无默认值参数:类型名
-
参数赋默认值(默认值的类型就是参数的类型)
有参数类型说明的好处:写代码时有对应数据类型的代码提示
-
返回值类型说明:-> 类型名
def func4(x: list, y=''):
pass
def func5(x: list, y='') -> list:
pass
5.4 不定长参数
不定长参数 - 一个形参可以同时接受多个实参(包括0个)
-
在参数名前加 * ,那么这个参数就可以同时接受多个实参(必须是位置参数)。
原理:带 * 的参数会变成一个元组,接受到的实参会变成元组中的元素。(如果参数是0个,则带 * 的参数就是一个空元组)
带 * 的参数的前面和后面还能有定长参数注意:带*的不定长参数在传参的时候只能用位置参数
(掌握!)重要结论:定义函数的时候,如果参数中有一个独立的*(*后无参数),*的作用是让在调用函数的时候*后面的参数必须用关键字参数传参。
-
在参数名前加 ** ,那么这个参数就可以同时接受多个实参(必须是关键字参数)。
原理:带**的参数会变成一个字典,接受到的实参会变成字典中的键值对。
带**的参数传参时,参数名可以任取。
# 练习:定义一个函数,求多个数的和
# sum1(10, 20) sum1(1, 2, 30) sum1(20, 3, 4, 5)
def sum1(*x):
pass
print(f'x:{x}')
sum1() # x:()
sum1(20) # x:(20,)
sum1(10, 20) # x:(10, 20)
sum1(10, 20, 34, 5, 6) # x:(10, 20, 34, 5, 6)
def func5(x, y, *z):
print(f'x:{x}, y:{y}, z:{z}')
func5(10, 20) # x:10, y:20, z:()
func5(10, 20, 30, 40) # x:10, y:20, z:(30, 40)
# 带*的参数的前面和后面还能有定长参数
def func5(x, *y):
print(f'x:{x},y:{y}')
func5(10, 20, 30)
# 结论:如果带*的不定长参数后面还有定长参数,那后边的定长参数必须通过关键字参数传参
def func6(*x, y):
print(f'x:{x},y:{y}')
# func5(10, 20, 30) # 报错,y必须以关键字参数传参
func6(10, 20, y=30) #x:(10, 20),y:30
# 定义函数的时候,如果参数中有一个独立的*(*后无参数),*的作用是让在调用函数的时候*后面的参数必须用关键字参数传参
def func8(x, *, y, z): # *(并不是表示一个不定长参数,因为*后面没有接参数)的价值就是让使用时y必须用关键字传参,即让*后的参数都必须用关键字传参
pass
func8(10, y=20, z=30)
# **
def func9(**x):
pass
func9() # {}
func9(a=10, b=20, c=30) # {'a': 10, 'b': 20, 'c': 30},传参时参数名可以任取取。



