程序地带

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



文章目录
十六、函数高级(续)8. 函数返回多个值9. 函数嵌套调用及过程- 函数嵌套- nonlocal 关键字
10. 递归函数的调用及过程(了解)1. 系统编程相关- pass- 无限循环- TODO 注释
**练习——函数版学生管理系统退出函数exit()- 代码实现
12. 函数的引用,函数名的赋值及函数作参数传递- 将一个函数的引用赋值给变量- 函数作为参数传递
12. 匿名函数 lambda- 格式:- lambda定义和普通函数的区别:- 使用场景:案例 - 计算器不要滥用 `eval`
十七、高阶函数1. map()函数- map()关系映射函数- 优化——利用lambda进行传参- 自定义实现map函数
2. reduce()函数- 使用- 应用——用reduce()求阶乘
3. filter()函数4. sort()函数高级


十六、函数高级(续)
8. 函数返回多个值

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


9. 函数嵌套调用及过程
- 函数嵌套

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


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


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


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


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


封装:数据隐藏 外部无法访问“嵌套函数”。贯彻 DRY(Don’t Repeat Yourself) 原则 嵌套函数,可以让我们在函数内部避免重复代码。闭包: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 步相关联。

代码特点


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

注意,递归的缺陷


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


应用:


# 阶乘
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定义和普通函数的区别:
lambda 没有函数名lambda 参数列表外没有括号lambda 函数体中,只能实现简单的表达式计算或函数调用lambda 函数体中,不能使用Return,if,while,for-in 这些都不行
return:lambda函数默认返回表达式的计算结果,不需要return lambda 函数体中,可以使用if 实现的三目运算符.
func = lambda m, n: m if m > n else n
print(func(1, 2)) # 2
- 使用场景:

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


eval 函数

功能:


eval()


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

语法:


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

参数:


source:一个 Python 表达式或函数 compile()返回的代码对象globals:可选。必须是 dictionarylocals:可选。任意映射对象
# 基本的数学计算
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
案例 - 计算器

需求


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

返回计算结果

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():函数会对参数序列中的元素进行累计


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


用传给reduce中的函数function(有两个参数)先对集合中的第1,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}]

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/qq_45725870/article/details/112689102

随机推荐

易汉博承建的三篇NAR的数据库

生物信息分析离不开数据资源和数据库,生物信息学数据库分类概览(第一版)系统梳理了常用功能数据库。下面再分析3个我们承建的NAR发表的新数据库,以飨读者。中医药方剂的数据库&...

刘永鑫Adam 阅读(800)