python基础05-函数强化和进阶

强化和进阶

函数强化和进阶

一、组包和拆包

1. 组包

  • = 右边有多个数据时, 会自动包装为元组
# 组包,1, 2, 3封装成元组再赋值,多变一
result = 10, 20, 30
print(result, type(result))  # (10, 20, 30) <class 'tuple'>

2. 拆包

  • 如果 变量数量 = 容器长度, 容器中的元素会一一对应赋值给变量
  • 拆包时要注意,需要拆的数据的个数要与变量的个数相同,否则程序会异常
  • 除了对元组拆包之外,还可以对列表、字典等拆包
# 拆包,一变多
a, b, c = (10, 20, 30)
print(a)  # 10
print(b)  # 20
print(c)  # 30

3. 应用场景

3.1 交换变量的值

a = 10
b = 20
a, b = b, a  # 先自动组包,后自动解包(拆包)

3.2 函数可以同时返回多个数

# 函数可以同时返回多个数
def return_arg():
    return 1, 2, 3


# 函数调用
# 变量名 = 函数()
ret = return_arg()
print(ret)

# 返回值直接做拆包
r1, r2, r3 = return_arg()
print(r1, r2, r3)

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)

二、引用

1. 引用

  • 引用:是一个变量或值的另一个名字,又称别名

    • 赋值本质:给右边的变量或值,起一个别名
  • 可以使用id函数查看变量的引用地址,

    引用地址相等,说明指向同一个内存空间

    • 每一次运行程序,每次地址都可能不一样
# a 是 10 的引用,10的别名是a,操作a就是操作10
a = 10
print(id(a), id(10))  # 地址id一样,指向同一个内存空间

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没有关系

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

三、可变类型与不可变类型

1. 可变类型和不可变类型

  1. 可变类型: 在存储空间中可以直接修改的数据类型
    • 列表 list
    • 字典 dict
    • 集合set
  2. 不可变类型: 在存储空间中不可以直接修改的数据类型
    • 数值类型 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

四、range

1. range的使用

  • range() 方法可创建一个整数列表对象,一般用在 for 循环中
    • 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)

五、列表推导式

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]

六、匿名函数

1. 匿名函数

  • 匿名函数是简单普通函数的简洁写法
  • 定义的函数没有名字,这样的函数叫做匿名函数

匿名函数的语法结构:

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')

七、递归函数

1. 什么是递归函数

  • 如果 一个函数在内部调用其本身,这个函数就是 递归函数
  • 递归函数一般会在特定情况下不再调用函数本身(一定要有出口),否则会导致到达最大递归次数, 程序报错

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)

八、enumerate、del

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'}

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'}]

九、学生名片管理系统

1. 示例代码

# 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()