在Python实际开发中,我们使用函数的目的只有一个“让我们的代码可以被重复使用”。函数的作用有两个:
在编程领域,编程可以分为两大类:① 模块化编程 ② 面向对象编程
所谓的函数就是一个被命名的、独立的、完成特定功能的代码段(一段连续的代码),并可能给调用它的程序一个返回值。
基本语法
def 函数名称([参数1, 参数2, ...]):
函数体
...
[return 返回值]
在Python中,函数和变量一样,都是先定义后使用。
# 定义函数
def 函数名称([参数1, 参数2, ...]):
函数体
...
[return 返回值]
# 调用函数
函数名称(参数1, 参数2, ...)
第一步:见到一个老师,打一声招呼
print('您好')
第二步:见到一个老师,打一声招呼
print('您好')
第二步:见到一个老师,打一声招呼
print('您好')
虽然以上程序可以满足程序的需求,但是我们发现,我们的代码做了很多重复性的工作。我们能不能对以上代码进行进一步的优化,避免代码的重复性编写。
# 定义函数(封装函数)
def greet():
print('您好')
# 调用函数
# 见到一个老师,打一声招呼
greet()
# 见到一个老师,打一声招呼
greet()
# 见到一个老师,打一声招呼
greet()
# 定义一个函数,同时为其定义一个参数
def greet(name):
print(f'{name},您好')
# 调用函数
# 见到了张老师,打一声招呼
greet('老张')
# 见到了李老师,打一声招呼
greet('老李')
# 见到了王老师,打一声招呼
greet('老王')
print()
等函数直接输出。# 定义一个函数,拥有name参数,同时函数执行完毕后,拥有一个return返回值
def greet(name):
# 执行一系列相关操作
return name + ',您好'
# 调用函数
# 见到了张老师,打一声招呼
print(greet('老张')) # 老张,您好
# 见到了李老师,打一声招呼
print("\033[0;31;40m\t" + greet('老李') + "\033[0m")
# 见到了王老师,打一声招呼
print("\033[0;36;40m\t" + greet('老王') + "\033[0m")
终端颜色参考:https://www.cnblogs.com/zhuminghui/p/9457185.html
思考1
如果一个函数如些两个return (如下所示),程序如何执行?
def return_num():
return 1
return 2
result = return_num()
print(result) # 1
答:只执行了第一个return,原因是因为return可以退出当前函数,导致return下方的代码不执行。
思考2
如果一个函数要有多个返回值,该如何书写代码?
答:在Python中,理论上一个函数只能返回一个结果。但是如果我们向让一个函数可以同时返回多个结果,我们可以使用return 元组
的形式。
def return_num():
return 1, 2
result = return_num()
print(result)
print(type(result)) #
思考3
封装一个函数,参数有两个num1,num2,求两个数的四则运算结果
四则运算:加、减、乘、除
def size(num1, num2):
jia = num1 + num2
jian = num1 - num2
cheng = num1 * num2
chu = num1 / num2
return jia, jian, cheng, chu
# 调用size方法
print(size(20, 5))
思考:定义一个函数后,程序员如何书写程序能够快速提示这个函数的作用?
答:注释
思考:如果代码多,我们是不是需要在很多代码中找到这个函数定义的位置才能看到注释?如果想更方便的查看函数的作用怎么办?
答:函数的说明文档(函数的说明文档也叫函数的文档说明)
# 1、定义一个menu菜单函数
def menu():
pass
# 2、定义通讯录增加操作方法
def add_student():
""" 函数的说明文档:add_student方法不需要传递任何参数,其功能就是实现对通讯录的增加操作 """
pass
# 3、定义通讯录删除操作方法
def del_student():
pass
# 4、定义通讯录修改操作方法
def modify_student():
pass
# 5、定义通讯录查询操作方法
def find_student():
pass
help(函数名称)
案例
调用add_student()方法
help(add_student)
需求:封装一个函数,用于生成指定长度的验证码。
实现函数之前,需要思考:
str1=23456789abcdefghijkmnpqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ
# 定义一个generate_code()函数
def generate_code(num):
""" generate_code方法主要用于生成指定长度的验证码,有一个num参数,需要传递一个int类型的数值,其return返回结果为num长度的随机验证码 """
import random
# 第一步:定义一个字符串
str1 = "23456789abcdefghijkmnpqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ"
# 第二步:循环num次,代表生成num长度的字符串
code = ''
for i in range(num):
# 第三步:从字符串中随机抽取num个字符
index = random.randint(0, len(str1) - 1)
code += str1[index]
# 第四步:使用return返回验证码
return code
# 求帮助(查看generate_code函数的作用以及需要传递的参数)
# help(generate_code)
# 调用函数
print(generate_code(6))
所谓函数嵌套调用指的是一个函数里面又调用了另外一个函数。
Step over(F8)
:代码一步一步向下执行,但是遇到了函数以后,不进入函数体内部,直接返回函数的最终的执行结果。Step into(F7)
:代码一步一步向下执行,但是遇到了函数以后,进入到函数体内部,一步一步向下执行,直到函数体的代码全部执行完毕。变量作用域指的是变量的作用范围(变量在哪里可用,在哪里不可用),主要分为两类:局部变量和全局变量。
在Python中,定义在函数外部的变量就称之为全局变量;定义在函数内部变量就称之为局部变量。
# 定义在函数外部的变量(全局变量)
num = 10
# 定义一个函数
def func():
# 函数体代码
# 定义在函数内部的变量(局部变量)
i = 1
全局变量
在整个程序范围内都可以直接使用
str1 = 'hello'
# 定义一个函数
def func():
# 在函数内部调用全局变量str1
print(f'在局部作用域中调用str1变量:{str1}')
# 直接调用全局变量str1
print(f'在全局作用域中调用str1变量:{str1}')
# 调用func函数
func()
局部变量
在函数的调用过程中,开始定义,函数运行过程中生效,函数执行完毕后,销毁
# 定义一个函数
def func():
# 在函数内部定义一个局部变量
num = 10
print(f'在局部作用域中调用num局部变量:{num}')
# 调用func函数
func()
# 在全局作用域中调用num局部变量
print(f'在全局作用域中调用num局部变量:{num}')
普及小知识:计算机的垃圾回收机制
思考:如果有一个数据,在函数A和函数B中都要使用,该怎么办?
答:将这个数据存储在一个全局变量里面。
案例
如果把通讯录管理系统更改为模块化编程模式(程序 => 函数),面临问题:
# 定义全局变量
info = []
# 定义funcA函数
def funcA():
# 使用global声明全局变量
global info
# 向info全局变量中添加数据
info.append({...})
# 定义funcB函数
def funcB():
# 共享全局作用域中的全局变量info
for i in info:
...
这个会产生一个问题:我们能不能在局部作用域中对全局变量进行修改呢?
# 定义全局变量num = 10
num = 10
# 定义一个函数func
def func():
# 尝试在局部作用域中修改全局变量
num = 20
# 调用函数func
func()
# 尝试访问全局变量num
print(num)
最终结果:弹出10,所以由运行结果可知,在函数体内部理论上是没有办法对全局变量进行修改的,所以一定要进行修改,必须使用global
关键字。
# 定义全局变量num = 10
num = 10
# 定义一个函数func
def func():
# 尝试在局部作用域中修改全局变量
global num
num = 20
# 调用函数func
func()
# 尝试访问全局变量num
print(num)
# 定义全局变量
info = []
# 定义funcA函数:向全局变量中添加信息
def funcA():
# 使用global声明全局变量
global info
# 向info全局变量中添加数据
info.append({...})
# 定义funcB函数:查询功能,需要共享全局作用域中的通讯录信息
def funcB():
# 共享全局作用域中的全局变量info
for i in info:
...
def test1():
return 50
def test2(num):
print(num)
# 1. 保存函数test1的返回值
result = test1()
# 2.将函数返回值所在变量作为参数传递到test2函数
test2(result) # 50
在函数定义与调用时,我们可以根据自己的需求来实现参数的传递。在Python中,函数的参数一共有两种形式:① 形参 ② 实参
形参:在函数定义时,所编写的参数就称之为形式参数
实参:在函数调用时,所传递的参数就称之为实际参数
def greet(name): # name就是在函数greet定义时,所编写的参数(形参)
return name + ',您好'
# 调用函数
name = '老王'
greet(name) # 在函数调用时,所传递的参数就是实际参数
注意:虽然我们在函数传递时,喜欢使用相同的名称作为参数名称。但是两者的作用范围是不同的。name = ‘老王’,代表实参。其是一个全局变量,而greet(name)函数中的name实际是在函数定义时才声明的变量,所以其实一个局部变量。
理论上,在函数定义时,我们可以为其定义多个参数。但是在函数调用时,我们也应该传递多个参数,正常情况,其要一一对应。
def user_info(name, age, address):
print(f'我的名字{name},今年{age}岁了,家里住在{address}')
# 调用函数
user_info('Tom', 23, '美国纽约')
注意事项:位置参数强调的是参数传递的位置必须一一对应,不能颠倒
函数调用,通过“键=值”形式加以指定。可以让函数更加清晰、容易使用,同时也清除了参数的顺序需求。
def user_info(name, age, address):
print(f'我的名字{name},今年{age}岁了,家里住在{address}')
# 调用函数(使用关键词参数)
user_info(name='Tom', age=23, address='美国纽约')
缺省参数也叫默认参数,用于定义函数,为参数提供默认值,调用函数时可不传该默认参数的值(注意:所有位置参数必须出现在默认参数前,包括函数定义和调用)。
def user_info(name, age, gender='男'):
print(f'我的名字{name},今年{age}岁了,我的性别为{gender}')
user_info('李林', 25)
user_info('振华', 28)
user_info('婉儿', 18, '女')
谨记:我们在定义缺省参数时,一定要把其写在参数列表的最后侧
不定长参数也叫可变参数。用于不确定调用的时候会传递多少个参数(不传参也可以)的场景。此时,可用包裹(packing)位置参数,或者包裹关键字参数,来进行参数传递,会显得非常方便。
def user_info(*args):
# print(args) # 元组类型数据,对传递参数有顺序要求
print(f'我的名字{args[0]},今年{args[1]}岁了,住在{args[2]}')
# 调用函数,传递参数
user_info('Tom', 23, '美国纽约')
def user_info(**kwargs):
# print(kwargs) # 字典类型数据,对传递参数没有顺序要求,格式要求key = value值
print(f'我的名字{kwargs["name"]},今年{kwargs["age"]}岁了,住在{kwargs["address"]}')
# 调用函数,传递参数
user_info(name='Tom', address='美国纽约', age=23)
kw = keyword + args
综上:无论是包裹位置传递还是包裹关键字传递,都是一个组包的过程。
组包:就是把多个数据组成元组或者字典的过程。
拆包就是把元组或字典中的数据单独的拆分出来,然后赋予给其他的变量。
拆包: 对于函数中的多个返回数据, 去掉元组, 列表或者字典直接获取里面数据的过程。
def func():
# 经过一系列操作返回一个元组
return 100, 200 # tuple元组类型的数据
# 定义两个变量接收元组中的每个数组(拆包)
num1, num2 = func()
# 打印num1和num2
print(num1)
print(num2)
注意:字典拆包,只能把每个元素的key拆出来
dict1 = {'name':'小明', 'age':18}
# 拆包的过程(字典)
a, b = dict1
print(a)
print(b)
# 获取字典中的数据
print(dict1[a])
print(dict1[b])
案例
使用至少拆包方式交换两个变量的值。
a = 10
b = 2
a, b = b, a
原理:
需求:进入系统显示系统功能界面,功能如下:
系统共6个功能,用户根据自己需求选取
模块化的编程思想是最早期的编程思想,其强调把一个系统分解为若干个功能,每个功能就是一个模块(函数)。当所有功能开发完毕后,则系统就完成了。
# 1、封装一个menu函数,专门用于打印选择界面菜单
def menu():
print('-' * 40)
print('通讯录管理系统V1.0')
print('1、添加学员信息')
print('2、删除学员信息')
print('3、修改学员信息')
print('4、查询学员信息')
print('5、遍历所有学员信息')
print('6、退出系统')
print('-' * 40)
# 6、定义一个全局变量
info = []
# 5、定义add_student方法,用于添加学员信息
def add_student():
# 定义一个空字典,接收name,age,mobile
info_dict = {}
# 提示用户输入学员信息name、age、mobile
info_dict['name'] = input('请输入学员姓名:')
info_dict['age'] = int(input('请输入学员年龄:'))
info_dict['mobile'] = input('请输入学员电话:')
# 声明全局变量info
global info
# 追加数据到info列表中
info.append(info_dict)
print('学员信息添加成功')
print(info)
# 7、定义del_student方法,用于删除学员信息
def del_student():
# 提示用户输入要删除学员的信息
name = input('请输入您要删除学员的姓名:')
# 判断name是否存在于info中的字典里 [{'name':'yogeek'}, {}, {}]
for i in info:
if i['name'] == name:
info.remove(i)
print('学员信息删除成功')
print(info)
break
else:
print('暂未查询到您要删除的学员信息')
# 8、定义modify_student方法,用于修改学员信息
def modify_student():
# 提示用户输入要修改学员的信息
name = input('请输入您要修改学员的姓名:')
global info
# 判断name是否存在于info中的字典里 [{'name':'yogeek', 'age':18, 'mobile':'10086'}, {}, {}]
for i in info:
if i['name'] == name:
i['name'] = input('请输入修改后的姓名:')
i['age'] = input('请输入修改后的年龄:')
i['mobile'] = input('请输入修改后的电话:')
print('学员信息修改成功')
print(info)
break
else:
print('暂未查询到您要修改的学员信息')
# 9、定义show_student方法,用于查询某个学员信息
def show_student():
# 提示用户输入要修改学员的信息
name = input('请输入您要查询学员的姓名:')
# 循环遍历,判断name是否存在
for i in info:
if i['name'] == name:
print(f'学员姓名:{i["name"]},学员年龄:{i["age"]},学员电话:{i["mobile"]}')
break
else:
print('暂未查询到您要查询的学员信息')
# 10、定义show_all方法,用于遍历所有学员信息
def show_all():
# 直接对info进行遍历操作
for i in info:
print(f'学员姓名:{i["name"]},学员年龄:{i["age"]},学员电话:{i["mobile"]}')
# 4、编写死循环,让程序可以一直执行下去
while True:
# 打印功能菜单
menu()
# 2、使用input方法接收用户的输入信息
user_num = int(input('请输入您要操作的功能序号:'))
# 3、使用if多分支条件实现不同的功能
if user_num == 1:
# 添加学员信息
add_student()
elif user_num == 2:
# 删除学员信息
del_student()
elif user_num == 3:
# 修改学员信息
modify_student()
elif user_num == 4:
# 查询学员信息
show_student()
elif user_num == 5:
# 遍历所有学员信息
show_all()
elif user_num == 6:
# 退出系统
print('感谢您使用通讯录管理系统V1.0')
break
else:
print('信息输入错误,请重新输入...')