Python基础-16 函数高级(续)

十六、函数高级(续)

8. 函数返回多个值

当在函数中,需要返回多个值的情况下,可以在return 后面直接将多个值写出来
解释器在返回时,会将多个值自动进行组包

9. 函数嵌套调用及过程

- 函数嵌套

函数嵌套是指,在一个函数的函数体内,又去调用了另外一个函数

如果函数内调用了另一个函数,那么当前函数会中断执行,跳转到另一个函数位置进行执行,被调用执行结束后,才回到当前函数恢复中断,继续执行

无论函数如何调用: 谁调用函数,被调用函数执行完就返回到谁那去

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-n3hyJq00-1610720718257)(Media/Xnip2019-04-19_10-08-38.png)]

一般在什么情况下使用嵌套函数?

  1. 封装:数据隐藏 外部无法访问“嵌套函数”。
  2. 贯彻 DRY(Don’t Repeat Yourself) 原则 嵌套函数,可以让我们在函数内部避免重复代码。
  3. 闭包:Enclosed 指的是嵌套函数(一个函数包裹另一个函数,闭包)
    • LEGB规则中有提到闭包概念

- nonlocal 关键字

  • nonlocal 用来声明外层的局部变量。
  • global 用来声明全局变量。
def outer():
    b = 10

    def inner():
        nonlocal b  # 申明外部函数的局部变量
        print('inner:', b)
        b = 20

    inner()
    print('outer b:', b)


outer()

用于函数嵌套

10. 递归函数的调用及过程(了解)

递归调用是一种特殊的嵌套调用,即一个函数 内部 调用自己

本质就是自己调用自己

利用递归可以用简单的程序来解决一些复杂的问题。比如:

  • 斐波那契数列的计算
  • 汉诺塔
  • 快排等问题

递归结构包括两个部分:

  • 定义递归头
    • 什么时候不调用自身方法。如果没有头,将陷入死循环,也就 是递归的结束条件。
  • 递归体
    • 什么时候需要调用自身方法。

递归步骤

  • 把第 n 步的值和第 n-1 步相关联。

代码特点

  1. 函数内部的 代码 是相同的,只是针对 参数 不同,处理的结果不同
  2. 参数满足一个条件 时,函数不再执行
    • 这个非常重要,通常被称为递归的出口,否则 会出现死循环
    • 一般用于返回值,不再调用自己。

注意,递归的缺陷

递归函数由于会创建大量的函数对象、过量的消耗内存和运算能力。在处理大量数据时,谨 慎使用。

应用:

# 阶乘
def factorial(n):
    if n == 1:
        return 1
    return n * factorial(n-1)

print(factorial(5))

'''过程
factorial(5) 
	-> 5 * factorial(4)				-> reutrn 5 *(4 * 3 * 2 * 1)  -> 120

		-> 4 * factorial(3)			-> return 4 *(3 * 2 * 1)
                
			-> 3 * factorial(2)		->  reutrn 3 *(2 * 1)
                    
				-> 2 * factorial(1)	-> return 2 *(1)
                            
                            -> return 1
'''

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FakUllxx-1610720718259)(Media/image-20210103182805468.png)]

# 数字累加
def sum_numbers(num):

    if num == 1:
        return 1
    
    # 假设 sum_numbers 能够完成 num - 1 的累加
    temp = sum_numbers(num - 1)

    # 函数内部的核心算法就是 两个数字的相加
    return num + temp

print(sum_numbers(2))

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-aEfes7QZ-1610720718261)(media/002_递归调用示意图.png)]

提示:递归是一个 编程技巧,初次接触递归会感觉有些吃力!在处理 不确定的循环条件时,格外的有用,例如:遍历整个文件目录的结构

1. 系统编程相关

- pass
  • pass 就是一个空语句,不做任何事情,一般用做占位语句
  • 是为了保持程序结构的完整性
- 无限循环
  • 在开发软件时,如果 不希望程序执行后 立即退出
  • 可以在程序中增加一个 无限循环
  • 由用户来决定 退出程序的时机
- TODO 注释
  • # 后跟上 TODO,用于标记需要去做的工作
# TODO(作者/邮件) 显示系统菜单

**练习——函数版学生管理系统

这个程序要理解记住的是逻辑,而不是代码

(个人)需要记住

def search_stu_with_id(stu_id):
    # 遍历每个学生
    for stu in students:
        if stu['id'] == stu_id:
            return stu
    # 返回没找到
    else:
        print(f'学号为{stu_id}的学生不存在')
        return 0

这里的for-else使用:当遍历完成,即没有return stu时,执行else后的语句

退出函数exit()

exit(0) # 程序通过 exit() 方法,可以直接结束程序

  • 退出码0
    • 这里的0代表退出程序后显示的数字
    • 0一般代表正常退出

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RBCJFYtC-1610720718267)(Media/image-20201229203007345.png)]

- 代码实现

'''
学生管理系统


程序 分析:
    1. 学生怎么表示
    2. 学生可能使用 学号 id  ,姓名  name, 年龄 age ,可以使用一个字典来表示每一个学生
    3. 应该有一个容器去保存所有的学生字典 ,可以使用列表实现
    4. 应该有一个主控函数
    5. 菜单函数
    5-1. 选择功能的函数
    6. 添加学生函数
    7. 修改学生函数
    8. 查找学生函数
    9. 删除学生函数
    10.显示所有学生的函数
    11. 因为创建 学生和修改学生,都需要从键 盘输入 数据,
    那么输入 数据这个功能 就可以提取出一个函数,返回输入的数据
    12. 添加 一个功能 函数,用来显示每个学生的信息
'''

# 1. 定义一个学生的列表,用来保存来管理学生

students = []


# 2. 主控函数


def main():
    # 通过 死循环控制程序可以重复运行
    while True:
        # 显示菜单
        show_menu()
        # 键盘输入选择一个功能
        select_id = input('请输入一个功能id:')
        # 根据输入调用相应的功能 函数
        operator(select_id)


def show_menu():
    print("---------------------------")
    print("      学生管理系统 V1.0")
    print(" 1:添加学生")
    print(" 2:删除学生")
    print(" 3:修改学生")
    print(" 4:查询学生")
    print(" 5:显示所有学生")
    print(" 6:退出系统")
    print("---------------------------")


# 参数是传递的用来选择的功能 id
def operator(select_id):
    if select_id == '1':
        add_stu()
    elif select_id == '2':
        stu_id = input('请输入要删除的学生id:')
        del_stu(stu_id)
    elif select_id == '3':
        modify_id = input('请输入要修改的学生id:')
        modify_stu(modify_id)
    elif select_id == '4':
        stu_id = input('请输入要查找的学生id:')
        stu = search_stu_with_id(stu_id)
        show_stu_info(stu)
    elif select_id == '5':
        show_all_info()
    elif select_id == '6':
        exit(0)
    else:
        print('输入错误,请重新输入')
        # break  # 因为选择功能没有在循环中,所以不能break
        # return  # 作用同上,函数返回后,返回到调用处,返回到主控函数中的死循环中,所以程序还是不能结束
        # 程序通过 exit() 方法,可以直接结束程序


# 实现一个输入函数
# 用来从键盘获取学生信息,并返回
# 学号 id  ,姓名  name, 年龄 age
def input_stu_info():
    # 保存输入的学生信息
    print('请输入学生信息:')
    id = input('请输入学号 id:')
    name = input('请输入姓名  name:')
    age = input('请输入年龄 age:')
    # 同时返回多个数据时,会组包成一个元组
    stu = id, name, age
    return stu


# 实现 添加函数
def add_stu():
    # 主体思路 就是向列表 中添加 一个字典
    # 创建一个学生字典 ,空的
    stu_dict = {}
    # 调用 输入函数,获取学生信息
    stu_tup = input_stu_info()
    # 利用获取的信息为字典添加数据
    stu_dict['id'] = stu_tup[0]
    stu_dict['name'] = stu_tup[1]
    stu_dict['age'] = stu_tup[2]
    # 将字典加到列表中
    global students
    students.append(stu_dict)
    # print(stu_list)


# 实现学生查找的功能
# 返回被找到的学生
def search_stu_with_id(stu_id):
    # 遍历每个学生
    for stu in students:
        if stu['id'] == stu_id:
            return stu
    # 返回没找到
    else:
        print(f'学号为{stu_id}的学生不存在')
        return 0



# 实现一个用来显示 单个学生信息的函数
def show_stu_info(stu):
    if stu != 0:
        print(f'学号:{stu["id"]},姓名:{stu["name"]},年龄:{stu["age"]}')


# 实现删除学生的函数
def del_stu(del_id):
    # 找到要删除的学生
    stu_dict = search_stu_with_id(del_id)
    # 从列表中删除
    if stu_dict == 0:
        print('删除失败')
    else:
        students.remove(stu_dict)
        print('删除成功')


# 实现 修改学生的函数
def modify_stu(modify_id):
    # 查找学生
    stu = search_stu_with_id(modify_id)
    # 如果找到就修改
    if stu == 0:
        print('修改失败')
    else:
        del_stu(modify_id)
        add_stu()
        print('修改成功')

    # 先去调用 输入 函数获取数据

    # 利用获取的信息为字典添加数据


# 显示所有学生信息
def show_all_info():
    # 遍历打印
    for stu in students:
        show_stu_info(stu)


# 执行主控函数,运行程序
main()

12. 函数的引用,函数名的赋值及函数作参数传递

- 将一个函数的引用赋值给变量

def show():
    print('hello python')

show()

#将一个函数的引用赋值给变量

func = show  # 注意这里不能加'()',因为加了括号代表调用执行这个函数
print(func)  # 输出:<function show at 0x000002880AA041F8>

func()  # 调用了show()
  • 注意这里不能加(),因为加了括号代表调用执行这个函数
  • 同样可以通过新的变量名(),来调用这个函数
  • 作用:可以实现一个可以调用另外一个函数的函数
# 可以实现一个可以调用另外一个函数的函数
def show():
    print('hello python')

def call_function(func):
    func()
call_function(show)  # show不带括号

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WjIOwpCa-1610720718270)(Media/Xnip2019-04-20_09-58-21.png)]

- 函数作为参数传递

函数作为参数传递时,同样不需要加括号,只需传递函数名即可

因为如果加了括号,定于是运行了这个函数

12. 匿名函数 lambda

def 函数名(参数列表):
函数体

- 格式:

变量 = lambda [形参1], [形参2], ... : 函数体只能是 [单行表达式][函数调用]
func = lambda: 1 + 1
print(func)  # <function <lambda> at 0x0000022D46A540D8>
print(func())  # 2

func = lambda x: print(x ** 10)
func(2)  # 1024

- lambda定义和普通函数的区别:

  1. lambda 没有函数名
  2. lambda 参数列表外没有括号
  3. lambda 函数体中,只能实现简单的表达式计算或函数调用
  4. lambda 函数体中,不能使用Return,if,while,for-in 这些都不行
    • return:lambda函数默认返回表达式的计算结果,不需要return
  5. lambda 函数体中,可以使用if 实现的三目运算符.
func = lambda m, n: m if m > n else n
print(func(1, 2))  # 2

- 使用场景:

一般情况下,因为lambda的局限性,使得他不能实现复杂功能,只能实现一些简单功能
那么在使用时,一般会实现一个简单的,一次性使用的场景

  1. eval 函数

功能:

eval()

  • 将字符串 当成 有效的表达式 来求值 并返回计算结果
  • 或将字符串当成有效代码来执行

语法:

eval(source[, globals[, locals]]) -> value

参数:

  • source:一个 Python 表达式或函数 compile()返回的代码对象
  • globals:可选。必须是 dictionary
  • locals:可选。任意映射对象
# 基本的数学计算
In [1]: eval("1 + 1")
Out[1]: 2

# 字符串重复
In [2]: eval("'*' * 10")
Out[2]: '**********'

# 将字符串转换成列表
In [3]: type(eval("[1, 2, 3, 4, 5]"))
Out[3]: list

# 将字符串转换成字典
In [4]: type(eval("{'name': 'xiaoming', 'age': 18}"))
Out[4]: dict
s = "print('abcde')"
eval(s)  # abcde


a = 10
b = 20
c = eval("a+b")
print(c)  # 30


dict1 = dict(a=100,b=200)
d = eval("a+b",dict1)
print(d)  # 300

案例 - 计算器

需求

  1. 提示用户输入一个 加减乘除混合运算

  2. 返回计算结果

    input_str = input(“请输入一个算术题:”)

    print(eval(input_str))

不要滥用 eval

eval 函数会将字符串当做语句来执行,因此会被注入安全隐患。比如:字符串中含有删除文 件的语句。那就麻烦大了。因此,使用时候,要慎重!!!

在开发时千万不要使用 eval 直接转换 input 的结果

__import__('os').system('ls')
  • 等价代码

    import os

    os.system(“终端命令”)

  • 执行成功,返回 0

  • 执行失败,返回错误信息

十七、高阶函数

1. map()函数

- map()关系映射函数

map():会根据提供的函数对指定序列映射

my_list = [i for i in range(5)]
print(my_list)  # [0, 1, 2, 3, 4]

# 这个函数是为了给map的参数进行传参
# 所以这个函数有且只能有一个参数
def f(x):
    return x ** 2


result = map(f, cl)
print(type(result))  # <class 'map'>
print(result)  # <map object at 0x000001FB8931F088>
print(list(result))  # [0, 1, 4, 9, 16]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GFf3pfOX-1610720718272)(Media/IMG_1138(20201230-112433)].JPG)

- 优化——利用lambda进行传参

# 利用lambda替代函数进行传参
my_list = [1, 2, 3, 4, 5]
result = map(lambda x: x ** 2, my_list)
print(type(result))  # <class 'map'>
print(result)  # <map object at 0x000001DE3C291048>
print(list(result))  # [1, 4, 9, 16, 25]

- 自定义实现map函数

# 自定义实现map函数

def my_map(func, c_list):
    result = []
    for i in c_list:
        result.append(func(i))
    return result


my_list = [1, 2, 3, 4, 5]
result = my_map(lambda x: x ** 2, my_list)
print(type(result))  # <class 'map'>
print(result)  # <map object at 0x000001DE3C291048>
print(list(result))  # [1, 4, 9, 16, 25]

2. reduce()函数

- 使用

reduce():函数会对参数序列中的元素进行累计

函数将一个数据集合中的所有数据进行下列操作

  1. 用传给reduce中的函数function(有两个参数)先对集合中的第1,2个元素进行操作
  2. 得到的结果在于第三个数据用function函数运算,最后得到一个结果
import functools

my_list = list('hello') # ['h', 'e', 'l', 'l', 'o']

result = functools.reduce(lambda s1, s2: s1 + s2, my_list)
print(result)  # 'hello'

- 应用——用reduce()求阶乘

# 练习——使用reduce求阶乘

import functools

my_list = [i for i in range(1, 6)]  # [1, 2, 3, 4, 5]

result = functools.reduce(lambda s, n: s * n, my_list)
print(result)  # 120

3. filter()函数

filter():用于过滤序列,过滤掉不符合调价按的元素,返回一个filter对象

  • 如果要转换为列表,可以使用list()来转换
# 过滤偶数
my_list = [i for i in range(1, 11)]  # [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

new_list = list(filter(lambda x: x % 2 == 0, my_list))
print(new_list)  # [2, 4, 6, 8, 10]
# 过滤出所有的数字字符串
my_list = ['123', '234', 'abc', '@#$', '  ', 'abc234', '132abc']
num_list = list(filter(lambda s: s if s.isdigit() else None, my_list))
print(num_list)  # ['123', '234']

4. sort()函数高级

通过lambda指定key,根据key值对列表中的字典进行排序

my_list.sort(key=lambda d: d[‘id’])

my_list = [
    {'id': 3, 'name': 'Tom', 'age': 18},
    {'id': 1, 'name': 'Jack', 'age': 21},
    {'id': 2, 'name': 'Rose', 'age': 20}
]

print(my_list)  
# [{'id': 3, 'name': 'Tom', 'age': 18}, 
# {'id': 1, 'name': 'Jack', 'age': 21}, 
# {'id': 2, 'name': 'Rose', 'age': 20}]

my_list.sort(key=lambda d: d['id'])
print(my_list)  
# [{'id': 1, 'name': 'Jack', 'age': 21}, 
# {'id': 2, 'name': 'Rose', 'age': 20}, 
# {'id': 3, 'name': 'Tom', 'age': 18}]

# 年龄降序排序
my_list.sort(key=lambda d: d['age'], reverse=True)
print(my_list)
# [{'id': 1, 'name': 'Jack', 'age': 21}, 
# {'id': 2, 'name': 'Rose', 'age': 20}, 
# {'id': 3, 'name': 'Tom', 'age': 18}]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值