学习目标:
- 能够掌握组包和拆包的使用,例如:交换两个变量的值,函数同时返回多个值
- 知道可变类型与不可变类型有哪些
- 能够通过for和range配合控制循环范围
- 能够使用列表推导式创建包含1-100之间元素的列表
- 能够通过匿名函数编写简单的函数
- 了解函数递归的调用流程
- 能够完成学生名片管理系统案例:增、删、改、查
01_组包和拆包
学习目标:
- 能够掌握组包和拆包的使用,例如:交换两个变量的值,函数同时返回多个值
1.1 组包
- = 右边有多个数据时, 会自动包装为元组
# 组包,1, 2, 3封装成元组再赋值,多变一
result = 10, 20, 30
print(result, type(result)) # (10, 20, 30) <class 'tuple'>
1.2 拆包
- 如果 变量数量 = 容器长度, 容器中的元素会一一对应赋值给变量
- 拆包时要注意,需要拆的数据的个数要与变量的个数相同,否则程序会异常
- 除了对元组拆包之外,还可以对列表、字典等拆包
# 拆包,一变多
a, b, c = (10, 20, 30)
print(a) # 10
print(b) # 20
print(c) # 30
1.3 应用场景
1.3.1 交换变量的值
a = 10
b = 20
a, b = b, a # 先自动组包,后自动解包(拆包)
1.3.2 函数可以同时返回多个数
# 函数可以同时返回多个数
def return_arg():
return 1, 2, 3
# 函数调用
# 变量名 = 函数()
ret = return_arg()
print(ret)
# 返回值直接做拆包
r1, r2, r3 = return_arg()
print(r1, r2, r3)
1.3.3 字典元素拆包
info_dict = {'name': 'mike', 'age': 34}
# 遍历字典,取出每一个item
for temp in info_dict.items():
print(temp) # 元组:(key, value)
key, value = temp # 元组拆包
print(key, value)
02_引用
学习目标:
- 知道引用是别名的意思
- 能够使用id函数获取变量的地址
2.1 引用
- 引用:是一个变量或值的另一个名字,又称别名
- 赋值本质:给右边的变量或值,起一个别名
- 可以使用 id函数 查看变量的引用地址,引用地址相等,说明指向同一个内存空间
- 每一次运行程序,每次地址都可能不一样
# a 是 10 的引用,10的别名是a,操作a就是操作10
a = 10
print(id(a), id(10)) # 地址id一样,指向同一个内存空间
2.2 引用指向改变
# a 是 10 的引用,10的别名是a,操作a就是操作10
a = 10
print(id(a), id(10)) # 地址id一样,指向同一个内存空间
# b 是 a 的引用,b的别名是a,操作a就是操作b
b = a
print(id(b), id(a)) # 地址id一样,指向同一个内存空间
print(a, b) # 10 10
# b 是 20 的引用,20的别名是b,操作b就是操作20
# b已经和上面的a没有关系,现在是20的别名
b = 20
print(b, id(b)) # 和a的地址不一样了,说明b和a没有关系
2.3 函数传参是引用传递
- 函数传参是引用传递
# 给函数传参是引用传递
# 带参数函数定义
def func(num):
print('func = ', id(num))
# 给函数传参,变量传参
a = 10
print('func调用前 = ', id(a))
func(a)
print('func调用后 = ', id(a))
运行结果:
func调用前 = 4404906944
func = 4404906944
func调用后 = 4404906944
03_可变类型与不可变类型
学习目标:
- 知道可变类型与不可变类型有哪些
3.1 可变类型和不可变类型
-
可变类型: 在存储空间中可以直接修改的数据类型
- 列表 list
- 字典 dict
- 集合set
-
不可变类型: 在存储空间中不可以直接修改的数据类型
- 数值类型 int, bool, float
- 字符串 str
- 元组 tuple
"""
可变类型: 列表、字典、集合
不可变类型: 数字类型(int, bool, float)、字符串、元组
可变类型:在地址不变的情况下,可以修改内容
不可变类型: 在地址不变的情况下,不可修改内容
"""
# 验证列表是可变类型
my_list = ['a', 'b']
print('改之前的地址:', id(my_list))
my_list.append('c') # 追加元素
print('改之后的地址:', id(my_list)) # 地址和改之前一样
print(my_list) # ['a', 'b', 'c']
print('=' * 20)
# 验证int是不可变类型
a = 10
print('改之前的地址:', id(a))
a = 20 # a是20的别名,重新指向新的空间,和前面的a没有关系,不是改前面的内容
print('改之后的地址:', id(a)) # 和改之前地址不一样了
print(a) # 20
04_range
学习目标:
- 能够通过for和range配合控制循环范围
4.1 range的使用
- range() 方法可创建一个整数列表对象,一般用在 for 循环中
- range(开始位置, 结束位置,步长)
- 和切片用法差不多
- range(开始位置, 结束位置,步长)
# 1. 打印:0、1、2、3、4
# for i in range(5): # [0, 5)
for i in range(0, 5): # [0, 5)
print(i)
# 2. 1~100的累加
# 2.1 定义辅助变量
_sum = 0
# 2.2 for 控制循环范围
for i in range(1, 101):
# 2.3 累加
_sum += i
# 2.4 在循环外面打印累加结果
print(_sum)
# 3. 验证步长,打印:0、2、4
for i in range(0, 5, 2): # [0, 5)
print(i)
05_列表推导式
学习目标:
- 能够使用列表推导式创建包含1-100之间元素的列表
5.1 列表推导式
- 列表推导式:快速生成列表元素的表达形式,通过for添加列表元素的简洁写法
- 推导式基本格式: [计算公式 for 循环 if 判断]
- 特点:
- 每循环一次,将计算公式的结果添加到列表中
- 计算公式可以使用遍历出的数据
- for 遍历出的数据 必须满足 if 判断 才会使用计算公式生成元素
# 普通方法:遍历0~4范围的元素,这些元素添加到列表中
# 1. 空列表
new_list = []
# 2. range(5)遍历取数
for i in range(5):
# 2.1 取出来的元素追加到列表
new_list.append(i)
# 3. 循环外面,打印结果
print(new_list)
print('='*30)
# 通过列表推导式,实现上面的效果 [计算公式 for循环体]
# 1. for i in range(5), 取出0,放在i变量中,i追加到列表
# 2. 循环下一步,取出2,放在i变量中,i追加到列表
# 重复,直到退出循环
new_list2 = [i for i in range(5)]
print(new_list2)
print('='*30)
# 0~10之间数,偶数才添加到列表
# 普通方法实现
# 1. 空列表
new_list = []
# 2. range(11)遍历取数
for i in range(11):
# 2.1 取出来的元素是偶数的话,追加到列表
# 2.2 i % 2 == 0, i 对 2求余,结果为0,就是偶数
if i % 2 == 0:
new_list.append(i)
# 3. 循环外面,打印结果
print(new_list)
print('='*30)
# 列表推导式实现
# [i for i in range(11) if i % 2 == 0]
# 1. for i in range(11)取第一个元素
# 2. if i % 2 == 0
# 3. 上面满足条件的i, 条件到列表
new_list2 = [i for i in range(11) if i % 2 == 0]
print(new_list2)
运行结果:
[0, 1, 2, 3, 4]
==============================
[0, 1, 2, 3, 4]
==============================
[0, 2, 4, 6, 8, 10]
==============================
[0, 2, 4, 6, 8, 10]
06_匿名函数
学习目标:
- 能够通过匿名函数编写简单的函数
- 匿名函数是简单普通函数的简洁写法
- 定义的函数没有名字,这样的函数叫做匿名函数
- 匿名函数的语法结构:
lambda [形参1], [形参2], ... : [单行表达式] 或 [函数调用]
- 示例代码:
# 无参有返回值匿名函数
# a) 匿名函数整体就是函数名字, 函数名字()就是函数调用
ret = (lambda: 1 + 1)()
print(ret)
# b) 给匿名函数起一个函数名字,函数名字()就是调用函数
func = lambda: 1 + 1 # 给匿名函数起一个函数名字叫func
ret = func() # 返回值变量 = 函数名()
print(ret)
print('=' * 30)
# 有参有返回值匿名函数
# a. 直接调用匿名函数
ret = (lambda a, b: a - b)(30, 10)
print(ret)
# b. 先给匿名函数起名,再调用
func = lambda a, b: a - b
ret = func(30, 10)
print(ret)
-
匿名函数中不能使用 while 循环、for 循环,只能编写单行的表达式,或函数调用
-
匿名函数中返回结果不需要使用 return,表达式的运行结果就是返回结果
-
匿名函数中也可以不返回结果。例如:
lambda : print('hello world')
07_递归函数
学习目标:
- 了解函数递归的调用流程
7.1 什么是递归函数
-
如果 一个函数在内部调用其本身,这个函数就是 递归函数。
-
递归函数一般会在特定情况下不再调用函数本身(一定要有出口),否则会导致到达最大递归次数, 程序报错
7.2 通过递归函数实现阶乘
阶乘的规律:
1! = 1
2! = 2 × 1 = 2 × 1!
3! = 3 × 2 × 1 = 3 × 2!
4! = 4 × 3 × 2 × 1 = 4 × 3!
...
n! = n × (n-1)!
示例代码:
# 1. 定义函数(参数)
def func(n):
# 2. 如果我是 1 ,直接返回 1
if n == 1:
return 1
# 3. 否则,返回 n * 函数调用自己(n-1)
else:
ret = n * func(n-1)
return ret
# 函数调用
_ret = func(3)
print(_ret)
调用流程:
08_enumerate、del
学习目标:
- 能够通过 for 配合 enumerate 遍历容器同时获取元素索引位置、元素
- 能够通过del删除列表元素
8.1 enumerate 的使用
- 通过 for 配合 enumerate 遍历容器同时获取元素索引位置、元素
示例代码:
user_list = [{'name': 'mike', 'age': 34, 'tel': '110'},
{'name': 'yoyo', 'age': 18, 'tel': '120'}]
# 遍历列表,同时把索引位置能打印
# 普通方法实现
# 1. 定义索引位置变量
i = 0
# 2. for遍历列表,打印:索引、元素
for user_dict in user_list:
print(i, user_dict)
# 3. 索引位置+1
i += 1
print('=='*20)
# 通过enumerate方法实现
# enumerate(容器变量):获取到:元素位置,元素
for i, user_dict in enumerate(user_list):
print(i, user_dict)
运行结果:
0 {'name': 'mike', 'age': 34, 'tel': '110'}
1 {'name': 'yoyo', 'age': 18, 'tel': '120'}
========================================
0 {'name': 'mike', 'age': 34, 'tel': '110'}
1 {'name': 'yoyo', 'age': 18, 'tel': '120'}
8.2 通过del删除列表元素
- 通过del删除列表元素:
del 列表[索引]
示例代码:
user_list = [{'name': 'mike', 'age': 34, 'tel': '110'},
{'name': 'yoyo', 'age': 18, 'tel': '120'}]
# 通过del删除列表元素 del 列表[索引位置]
print(user_list) # [{'name': 'mike', 'age': 34, 'tel': '110'}, {'name': 'yoyo', 'age': 18, 'tel': '120'}]
# 删除索引位置为0的元素
del user_list[0]
print(user_list) # [{'name': 'yoyo', 'age': 18, 'tel': '120'}]
09_学生名片管理系统
学习目标:
- 能够完成学生名片管理系统案例:增、删、改、查
示例代码:
# 0. 函数的外面,定义一个全局变量(列表),用于保存用户信息
user_list = [{'name': 'mike', 'age': 34, 'tel': '110'},
{'name': 'yoyo', 'age': 18, 'tel': '120'}]
# 显示菜单函数定义
def show_menu():
print('=' * 20)
print('= 1. 添加学生')
print('= 2. 查询所有学生')
print('= 3. 查询某个学生')
print('= 4. 修改某个学生')
print('= 5. 删除某个学生')
print('= 6. 退出系统')
print('=' * 20)
# 定义新建学生的函数
def add_stu_info():
"""添加学生信息"""
# 1. 输入用户信息:姓名、年龄、电话
_name = input('请输入学生姓名:')
_age = int(input('请输入学生年龄:')) # 年龄应该是整型,所有做了int转换
_tel = input('请输入学生电话:')
# 2. 通过for遍历,取出某个元素后,这个元素就是字典
for user_dict in user_list:
# 2.1 字典[‘name’] == 用户输入的名字,是否相等,相等则跳出循环
if user_dict['name'] == _name:
print('此用户已经存在,请重来')
# 2.2 break跳出循环
break
else:
# 3. for中的else 如果用户不存在列表中,添加用户字典到列表
# 3.1 创建字典
info_dict = {'name': _name, 'age': _age, 'tel': _tel}
# 3.2 追加列表
# user_list是可变类型,没有重新赋值,没有改变原来地址,所以不用global声明
user_list.append(info_dict)
# 显示所有的学生,带序号的
def show_all_stu():
"""显示所有的学生"""
# 1. 遍历前,打印一些提示信息:序号 姓名 年龄 电话
# \t一个tab键的空格
print('序号\t\t姓名\t\t年龄\t\t电话')
# 2. 遍历 for 索引位置,字典 in enumerate(user_list):
for i, user_dict in enumerate(user_list):
# 2.1 打印一个用户的信息 索引位置+1,user_dict[‘name’]……
print('%d\t\t%s\t\t%d\t\t%s' % (i + 1, user_dict['name'], user_dict['age'], user_dict['tel']))
# 显示某个学生
def show_one_stu():
"""显示某个学生"""
# 1. 输入姓名
_name = input('请输入学生姓名:')
# 2. 通过for遍历,取出一个字典user_dict
for user_dict in user_list:
# 2.1 user_dict[‘name’]和输入姓名判断
if user_dict['name'] == _name:
# 2.1.1 如果相等,输出用户信息,退出循环
print('查询到的用户信息如下:')
print('%s\t%d\t%s' % (user_dict['name'], user_dict['age'], user_dict['tel']))
break
# 3. for中的else,循环执行完毕,没有break,说明用户不存在,提示一下
else:
print('查询的用户不存在')
def update_stu_by_name():
"""更新某个学生信息,根据输入的姓名匹配哪个学生"""
# 1. 输入需要修改的用户姓名
update_name = input('输入需要修改的用户姓名:')
# 2. for遍历,带索引的遍历 i, user_dict in user_list
for i, user_dict in enumerate(user_list):
# 2.1 如果user_dict['name']和输入用户名字相等
if user_dict['name'] == update_name:
# 2.1.1 重新输入新的姓名、年龄、电话
_name = input('请输入新的学生姓名:')
_age = int(input('请输入新的学生年龄:'))
_tel = input('请输入新的学生电话:')
# 2.1.2 对user_list[i]['name'] = 新的name
user_list[i]['name'] = _name
user_list[i]['age'] = _age
user_list[i]['tel'] = _tel
# 2.1.3 ……、修改成功打印、break跳出循环
print('修改成功')
break
# 3. for中的else 输入的用户不在列表
else:
print('输入的用户不在列表,请重新输入')
def del_stu_by_name():
"""删除某个学生,根据输入的姓名"""
# 1. 输入用户姓名
_name = input('请输入需要删除的名字:')
# 2. for遍历,带索引的遍历 i, user_dict
for i, user_dict in enumerate(user_list):
# 2.1 如果user_dict['name']和输入用户名字相等
if user_dict['name'] == _name:
# 2.1.1 del 列表[i], 同时break跳出循环
del user_list[i]
print('删除成功')
break
# 3. for中else 输入的用户在列表中,不存在
else:
print('用户不在列表中,无法删除')
# 写一个主程序
def main():
# 1. 死循环
while True:
# 调用菜单
show_menu()
# 2. 用户输入数字
cmd = input("请输入功能数字:")
# 3. 条件选择
if cmd == "1":
# print('添加学生')
add_stu_info()
# print(user_list) # 打印列表,做测试,看数据
elif cmd == "2":
# print('查询所有学生')
show_all_stu()
elif cmd == "3":
# print('查询某个学生')
show_one_stu()
elif cmd == "4":
# print('修改某个学生')
update_stu_by_name()
elif cmd == "5":
# print('删除某个学生')
del_stu_by_name()
elif cmd == "6":
print('退出循环')
break
else:
print('输入有误,请重新输入')
# 调用主程序
main()
强化和进阶——练习题
能力目标:
- 能够对元组进行拆包
- 知道列表、字典是Python中常见的可变类型
- 知道数字、字符串、元素是Python中常见的不可变类型
- 知道使用列表推导式能够创建包含1-100之间元素的列表
- 知道新建名片功能的实现思路
- 知道显示全部名片功能的实现思路
- 知道查询名片功能的实现思路
- 知道修改名片功能的实现思路
- 知道删除名片功能的实现思路
关卡一:基础题
1. 什么是组包?什么是拆包?
参考答案
组包: =右边有多个数据时, 会自动包装为元组 拆包: =如果 变量数量 = 容器长度, 容器中的元素会一一对应赋值给变量
2. 什么是可变类型?可变类型有哪些?什么是不可变类型?不可变类型有哪些?
参考答案
可变类型: 在地址不变的情况下,可以修改内容 ` 列表 list 字典 dict 集合 set 不可变类型: 在地址不变的情况下,不可修改内容 数值类型 int, bool, float 字符串 str 元组 tuple
3. Python中使用什么函数来查看变量的内存地址?
参考答案
id函数
4. 什么是列表推导式?格式是什么样的?有什么特点?
参考答案
列表推导式: 快速生成列表元素的表达形式 推导式基本格式: [计算公式 for循环 if判断] 特点: 每循环一次,将计算公式的结果添加到列表中 计算公式可以使用遍历出的数据 for遍历出的数据 必须满足if判断 才会使用计算公式生成元素
5. 定义匿名函数的格式是什么?
参考答案
lambda 形参列表:计算表达式
6. 什么是递归函数?
参考答案
一个函数在内部调用其本身,这个函数就是 递归函数。
关卡二:综合题
1. 设计一个程序
已知列表num, 完成列表num的去重,并使用一行代码完成num列表奇数的筛选
num = [1,1,2,3,4,4,5]
训练提示
set类型可以完成列表的去重,列表推导式可以一行代码完成奇数筛选
参考答案
num = list(set(num))
num = [i for i in num if i % 2 != 0]
2. 设计一个程序
-
用列表推导式求出100以内4的倍数:
参考答案
list1 = [i for i in range(1, 100) if i % 4 == 0]
print(list1)
3. 设计一个程序:
-
实现名片管理系统代码至少2遍,直到自己能根据运行效果,就能写出完整的程序代码
关卡三:扩展题
1. 设计一个程序
-
输出 9*9 乘法口诀表
提示:
1. 使用for循环嵌套,分行与列考虑,共9行9列,i控制行,j控制列
2. 使用range函数
1*1=1 2*1=2 2*2=4 3*1=3 3*2=6 3*3=9 4*1=4 4*2=8 4*3=12 4*4=16 5*1=5 5*2=10 5*3=15 5*4=20 5*5=25 6*1=6 6*2=12 6*3=18 6*4=24 6*5=30 6*6=36 7*1=7 7*2=14 7*3=21 7*4=28 7*5=35 7*6=42 7*7=49 8*1=8 8*2=16 8*3=24 8*4=32 8*5=40 8*6=48 8*7=56 8*8=64 9*1=9 9*2=18 9*3=27 9*4=36 9*5=45 9*6=54 9*7=63 9*8=72 9*9=81
参考答案
# i控制行
for i in range(1, 10):
# j控制列
for j in range(1, i+1):
print("%d*%d=%d " % (i, j, i*j), end="")
print()
2. 自行探究下面代码(偏难)
-
注意1: 本题要结合函数的使用, 以及引用的概念, 综合来看下面的代码. 看不懂没关系,到时候听讲解
-
注意2: 本题和第三题有关联关系. 如果看不懂的, 就暂时不用做第三题, 直接查看答案了解思路就行.
# 在PyCharm中拷贝下面代码, 尝试读懂下面的写法
# 思考: 为什么使用do函数中的action(), 但是调用了eat函数
# 1. 函数名, 其实也是一个变量, 也会有id地址
def eat():
print(id(eat), "吃东西")
def drink():
print(id(drink), "喝东西")
# 2. 只要是变量, 就可以传参, 因此, 函数名可以当做参数传递
def do(action):
# 3. 只要id相同, 就说明是同一个函数
print(id(action))
# 4. 函数名+()就是函数调用
action()
# 5. 想调用哪个函数, 就传递函数名.
do(eat) # 这样的写法有助于扩充程序功能. 增加了其他方法后, 调用方法不用变
3. 设计一个程序(偏难)
-
根据第二题的探究结果, 结合匿名函数, 实现下面需求
-
使用匿名函数,实现调用一个函数处理加减乘除。(不需要考虑被除数为 0 的情况。)
-
定义四个匿名函数实现加、减、乘、除运算
-
定义一个函数接收 两个数字 和 匿名函数,并使用匿名函数来处理两个数字
-
在函数中调用匿名函数,输出运算结果
提示:
1. 函数的参数是可以传入另一个函数名的
2. 每个运算定义一个匿名函数: add = lambda x, y: x + y**
3. 定义一个函数接收匿名函数, 并在该函数内实现匿名函数的调用:
-
参考答案
def compute(a, b, command):
res = command(a, b)
print(res)
add = lambda x, y: x + y
minus = lambda x, y: x - y
mul = lambda x, y: x * y
div = lambda x, y: x / y
compute(11, 22, add)