目录
1. 定义函数
def 函数名(形式参数1, 形式参数2, ...):
语句块
return [返回值] # 可以不返回值
函数声明必须使用 def 关键字;
2. 可以有多个返回值
如果程序要返回多个值,可以将这些值放到一个列表中再返回,也可以直接返回多个值,此时Python会自动将多个返回值放到元组中返回;
def sum_and_average(list):
sum = 0
count = 0
for i in list:
sum += i
count += 1
return sum, sum/count #直接返回,返回值为一个元组
# return [sum, sum/count] #以列表形式返回,返回值为一个列表
# 函数调用
my_list = list(range(20,30))
print(sum_and_average(my_list))
#直接输出返回值输出一个元组或者列表
sum, average = sum_and_average(my_list)
#也可以使用序列解包功能使用多个变量接收返回值,列表和元组都可以使用
print(sum, average)
3. 函数参数
1)调用函数时给参数赋值
调用函数时需要给形式参数传入值,有三种方式用于传入参数值:
a)位置参数:按照形参位置传入;
这种方式下必须严格按照定义函数时指定的顺序来传入参数值;
# 定义一个求面积的函数
def area(width, height):
return width*height
# 调用函数
a = area(10, 20)
print(a)
# 200
b)关键字参数:根据参数名传入参数值;
这种方式下无须遵守定义函数时形参的顺序;
# 定义一个求面积的函数
def area(width, height):
return width*height
# 调用函数
a = area(height=10, width=20)
print(a)
# 200
c)混合使用位置参数和关键字参数
这种方式下关键字参数必须位于位置参数之后;
2)参数默认值
调用函数可以不用为该形参传入参数值,直接使用参数的默认值;
注:定义函数时,有默认值的参数一般放到参数最后面;
# 定义一个求面积的函数
def area(width=10, height=20):
return width*height
# 调用函数
a = area()
print(a)
# 200
3)定义个数可变的参数值
一般我们定义一个形式参数然后调用函数时将一个列表传给该形参就可以达到将多个值传给函数;
我们同样可以使用另一种方法向函数参数传入多个值:
在形参前面添加一个 * ,就表示该形参可以接受多个参数值,多个参数值被当作元组传入;(这样的形参最多只能有一个)
def student(num, *subject):
print(num)
print(subject)
# 调用函数
student(2019111111, "凸优化", "云计算", "密码学")
# 输出结果:
# 2019111111
# ('凸优化', '云计算', '密码学')
假如一个函数的第一个参数就是可接受多个参数值的形式参数,调用时给后面的形式参数赋值必须使用关键字参数的形式传入值,否则所有的参数值都会被第一个参数接收;
也可以将多个关键字参数值传给一个形式参数,在形参前面添加 ** 号,表示该形参可接收多个关键字参数值;(这样的形参最多也只能有一个)python会将这些关键字参数值以字典形式传给形式参数;
def student(num, *subject, **grade):
print(num)
print(subject)
print(grade)
# 调用函数
student(2019111111, "凸优化", "云计算", "密码学", 凸优化=50, 云计算=60, 密码学=70)
# 输出结果:
# 2019111111
# ('凸优化', '云计算', '密码学')
# {'凸优化': 50, '云计算': 60, '密码学': 70}
4)将元组或列表的元素拆开后分别赋值给函数的参数
这种情况下需要在调用函数时对需要拆开赋值的列表或者元组前加 * ;
def student(name, sex):
print(name)
print(sex)
# 调用函数
list_1 = ["zhu", "man"]
student(*list_1)
# zhu
# man
如果是字典,字典前加 ** ;此时字典的key值必须为定义函数的参数名;
def student(name, sex):
print(name)
print(sex)
# 调用函数
dict_1 = {"name": "zhu", "sex": "man"}
student(**dict_1)
# zhu
# man
5)函数参数传递机制
python中函数的参数传递机制都是“值传递”,就是将实际参数值的副本传入函数,不管函数如何操作副本,实际参数值本身不受到任何影响;
def swap(a, b):
a, b = b, a
print('swap函数中a=', a)
print('swap函数中b=', b)
# 调用函数
a=10
b=15
swap(a, b)
print('执行结束后a=', a)
print('执行结束后b=', b)
# swap函数中a= 15
# swap函数中b= 10
# 执行结束后a= 10
# 执行结束后b= 15
程序开始定义了两个局部变量a,b,存储在栈里面,调用swap()函数时,系统又为swap()函数分配一块栈区,在swap()函数栈里分配两个存储空间存储a,b的副本,所以调用函数是对swap()栈区存储的a,b进行操作,主程序里的a,b没有发生变化;
注:当参数值为一个列表或者字典时,结果就会发生变化;
def swap(list):
list_1[0], list_1[1] = list_1[1], list_1[0]
print('swap函数中第一个元素等于:', list_1[0])
print('swap函数中第二个元素等于:', list_1[1])
# 调用函数
list_1 = [10, 15]
swap(list_1)
print('执行结束后第一个元素等于:', list_1[0])
print('执行结束后第二个元素等于:', list_1[1])
# swap函数中第一个元素等于: 15
# swap函数中第二个元素等于: 10
# 执行结束后第一个元素等于: 15
# 执行结束后第二个元素等于: 10
原因是因为list_1它是一个引用变量,它存储的是列表的地址,将其作为参数值传给函数参数时是将列表的地址副本传给参数,swap()函数根据该副本还是对字典本身进行操作,所以值发生了变化;
所以,想要通过函数对数据进行改变,就可以将其放到列表或字典中,然后赋值给函数参数;
4. 递归函数
在一个函数体内调用它自身;
为了结束递归,应设置一个递归结束条件;
# 已知有一个数列:f(0)=1, f(1)=4, f(n+2)=2*f(n+1)+f(n), 求f(m)
def f(m):
if m == 0:
return 1
if m == 1:
return 4
return 2*f(m-1)+f(m-2)
m_string = input("请输入要求值的m:")
m_int = int(m_string)
print(f(m_int))
5. 局部函数(在函数体内定义的函数)
默认情况下,局部函数对外部是透明的;
在局部函数中需要使用它所在函数中的局部变量:
def test():
name = "zhu"
def local_test():
print(name)
local_test()
test()
# zhu
如果在局部函数中定义的变量名和它所在函数中的局部变量名相同,局部函数内的变量会遮蔽它所在函数内的局部变量;
def test():
name = "zhu"
def local_test():
name = "xue"
print(name)
local_test()
test()
# xue
如下所示,由于在局部函数local_test()函数中使用了“ name="xue" ”语句,程序判定其重新定义了变量name,所以遮蔽了局部函数外面的name变量定义,但是在局部函数中还未定义就被print()函数调用,所以程序报错;
def test():
name = "zhu"
def local_test():
print(name)
name = "xue"
local_test()
test()
# 程序报错:未定义就引用
如果想要让程序明白局部函数中的name="xue"语句不是重新定义一个name变量,而是对该局部函数外面的变量赋值,使用nonlocal语句说明;
def test():
name = "zhu"
def local_test():
nonlocal name
print(name)
name = "xue"
local_test()
test()
# zhu