5.3 Python 闭包函数,递归函数,匿名函数

1. 函数对象

Python中所有的数据都是对象, 函数的值也是一个对象, 通过函数名获取函数对象.
使用函数名也就是使用函数对象, 函数对象加上括号立刻执行函数体代码块.
函数名的其它作用:
* 1. 函数名可以作为其它变量的值.
* 2. 函数名可以作为其它函数的参数.
* 3. 函数名可以作为函数的返回值.
* 4. 函数名可以作为容器类型的的元素.
1.1 引用函数变量
# 检测代码, 申请内存地址存储函数体代码块, 并将函数体代码块的内存地址绑定给标识符func1.
def func1():print('1')# func2 引用 func1的内存地址, 也就是函数体代码块的内存地址.
func2 = func1
# 加括号调用
func2()
1.2 做为参数
# 检测代码, 申请内存地址存储函数体代码块, 并将函数体代码块的内存地址绑定给标识符func1.
def func1():print('1')def func2(func):# 调用func1函数func1()  # 1# 函数名func1最为另一个函数的参数
func2(func1)
# 省略写法, 语句不明确, 不推荐.
def func1():print('1')def func2():# 可以直接使用到外部的名称func1()func2()
1.3 做为返回值
# 检测代码, 申请内存地址存储函数体代码块, 并将函数体代码块的内存地址绑定给标识符func1.
def func1():print('1')def func2():# 直接可以使用到外部的名称return func1func = func2()
func()  # 1
从外部范围隐藏名称xx.
Pycharm的提示需要重命名参数名称来消除这个警告.

2022-12-11_01679

# 取消从外部范围隐藏名称提示.
def func1():print('1')def func2(fun_p):# 直接可以使用到外部的名称return fun_pfunc = func2(func1)
func()  # 1
# 省略写法, 语句不明确, 不推荐.
def func1():print('1')def func2():# 直接可以使用到外部的名称return func1func = func2()
func()  # 1
1.4 做为容器元素
# 检测代码, 申请内存地址存储函数体代码块, 并将函数体代码块的内存地址绑定给标识符add_staff.
def add_staff():print('添加员工')# 检测代码, 申请内存地址存储函数体代码块, 并将函数体代码块的内存地址绑定给标识符del_staff.
def del_staff():print('删除员工')func_dic = {'1': add_staff, '2': del_staff}# 获取元素得到函数对象, 加上括号执行函数体代码.
func_dic['1']()  # 添加员工
func_dic['2']()  # 删除员工

2. 函数嵌套

2.1 嵌套调用
在函数中调用其它函数.
def func1():print('form func1')def func2():func1()  # form func1print('form func2')func2()  # form func2
2.2 嵌套死循环
两个函数体内互相调用函数, 默认只有1000层嵌套, 可以设置源码修改默认嵌套层数, 超出就报错:
: RecursionError: maximum recursion depth exceeded.
: 递归错误:超过了最大递归深度.
def func1():# 在func1中调用func2func2()def func2():# 在func2中调用func1func1()# 启动
func2()

2022-12-11_01680

2.3 函数嵌套定义
函数嵌套定义: 一个函数里用def语句来创建其它的函数的情况.
目的: 将复杂的功能全部隐藏, 暴露一个接口, 供操作者使用,
操作者不需要明白内部的代码是干什么的, 只需要知道接口的功能, 和使用方法即可.
def all_func(choices):def add_staff():print('添加员工')def find_only():print('查询员工')def modify_salary():print('修改薪资')def all_staff():print('所有信息')def del_staff():print('删除员工')func_dic = {'1': add_staff,'2': find_only,'3': modify_salary,'4': all_staff,'5': del_staff,}if choices in func_dic:func_dic[choices]()else:print('功能为开放!')while True:print("""1. 添加员工2. 查询员工3. 修改薪资4. 所有信息5. 删除员工""")choice = input('请输入编号>>>:')all_func(choice)

3. 闭包函数

闭包函数 = 函数对象 + 函数嵌套定义 + 名称空间与作用域.
闭包函数满足以下两个条件:
* 1. 闭函数: 定义在函数内部的函数, 闭包函数是一种为函数传参的方案.
* 2. 包函数: 内部局部函数引用了外层局部函数的名称.
3.1 直接传参
def func(x, y):print(x, y)func(1, 2)
3.2 闭包函数传参
# 演变过程1
def func1():x = 1y = 2def func2():# 在函数内部使用外部的函数的名称print(x, y)  # 1 2return func2func = func1()
func()
# 演变过程2
def func1(x, y):def func2():print(x, y)  # 1 2return func2func = func1(1, 2)
# 闭包函数
func()

4. 递归函数

递归函数: 在运行过程中直接或间接的调用自己, 一种基于函数实现循环.
默认嵌套1000, 超出报错, 可以设置参数修改嵌套层次, 某些电脑可能只能达到99?层.
递归是要有一定条件的:
* 1. 每次递推之后复杂度相较于上一次一定要有所下降.
* 2. 必须要能回溯.递归分两步:
* 1. 递推: 一层层往下推导结果, 递推满足某个条件后, 开始回溯.
* 2. 回溯: 依据最后的结果回溯得到最初问题的答案.
4.1 示例1
推导第一个个小孩子的年龄:
现在有五个小朋友: 1 2 3 4 5          递推总次数 count = 5    
第一个小朋友说比第二个小朋友大 2          count - 1   + 2 
第二个小朋友说比第三个小朋友大 2          count - 1   + 2 
第三个小朋友说比第四个小朋友大 2          count - 1   + 2 
第四个小朋友说比第五个小朋友大 2          count - 1   + 2 
第五个小朋友18                          count = 0  return 18   回溯 

image-20221212054838441

def get_age(count):count -= 1  # 递推重做的事if count == 0:  # 回溯的条件return 18return get_age(count) + 2  # 回溯放回重复做的事print(get_age(5))
# 省略写法
def get_age(count):if count == 1:return 18# 在这一步开始执行函数return get_age(count - 1) + 2  print(get_age(5))  # 26
4.2 示例2
打印出列表中每一个整型元素.
list1 = [1, [2, [3, [4, [5, [6, [7, [8, [9, [10, [11, [12, [13, [14, ]]]]]]]]]]]]]]
list1 = [1, [2, [3, [4, [5, [6, [7, [8, [9, [10, [11, [12, [13, [14, ]]]]]]]]]]]]]]def print_element(l1):# 遍历列表for i in l1:# 元素是整型则打印if type(i) == int:print(i)# 全是是嵌套列表, 则继续递归处理列表else:print_element(i)print_element(list1)
4.3 示例3
算法: 解决问题的最高效方式.
使用递归二分法快速找出序列序列的某个值. 查找的元素就在数据集的头尾那么该算法不是很高效.list1 = [11, 23, 43, 57, 68, 76, 81, 99, 123, 321, 432, 567, 666, 712, 899, 999, 1111]
将列表从中间一分为二, 判断中间的值, 比查找的值大还是小.
在每次的二分之一基础上筛选掉一半的值, 找到最后, 要么存在要么不存在.
l1 = [11, 23, 43, 57, 68, 76, 81, 99, 123, 321, 432, 567, 666, 712, 899, 999, 1111]# 查找的值
num = 23# 获取中间的值的索引, 整除
def find_num(list1, num):if not list1:print('没有这个数据')return# 获取中间值average = len(list1) // 2if list1[average] < num:# 获取右边的列表r_list = list1[average + 1:]find_num(r_list, num)elif list1[average] > num:# 获取右边的列表l_list = list1[:average]find_num(l_list, num)else:print('找到了')returnfind_num(l1, num)
l1 = [11, 23, 43, 57, 68, 76, 81, 99, 123, 321, 432, 567, 666, 712, 899, 999, 1111]def find_num(list1, num):# 结束条件 列表为空if len(list1) == 0:print('查找的数字不存在!')return# 定义一个中间值middle = len(list1) // 2  # 只能是整除 1//2 = 0print(middle, list1[middle], num)# 输入的值与中间值做比较if num < list1[middle]:# 比中间值小向 往列表的左←边查找list1 = list1[0:middle]find_num(list1, num)# 比中间值大向 往列表的右→边查找elif list1[middle] < num:list1 = list1[middle + 1:]find_num(list1, num)# 不大不小就找到了.else:print('找到了')returninput_num = int(input('输入查找的数字>>>:').strip())
find_num(l1, input_num)

5. 匿名函数

匿名函数: 指没有名字的函数, 通常只使用一次, 在需要一个函数, 但是又不想思考起名字时使用.
一般不会单独使用, 都是配合其他函数一起使用.
格式: lambda 形参: 计算返回值的表达式
返回形参处理的结果.
# 加上括号调用,  括号内传入参数
print((lambda x: x ** 2)(2))  
为匿名函数起名字, 会提示不规范:
: PEP8: E731 do not assign a lambda expression, use a def.
: PEP8: E731不指定lambda表达式,请使用def.
# 会出现PEP8提示
func = lambda x: x ** 2
res = func(2)
print(res)  # 4

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/26862.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

搜索与图论:染色法判别二分图

搜索与图论&#xff1a;染色法判别二分图 题目描述参考代码 题目描述 输入样例 4 4 1 3 1 4 2 3 2 4输出样例 Yes参考代码 #include <cstring> #include <iostream> #include <algorithm>using namespace std;const int N 100010, M 200010;int n, m; i…

多款可观测产品全面升级丨阿里云云原生 5 月产品月报

云原生月度动态 云原生是企业数字创新的最短路径。 《阿里云云原生每月动态》&#xff0c;从趋势热点、产品新功能、服务客户、开源与开发者动态等方面&#xff0c;为企业提供数字化的路径与指南。 趋势热点 &#x1f947; 阿里云云原生产品负责人李国强&#xff1a;推进可…

《Brave New Words 》9.1 AI 世界中的就业

Part IX: Work and What Comes Next 第九部分&#xff1a;工作及其未来发展 The one who plants trees, knowing that he will never sit in their shade, has at least started to understand the meaning of life. —Rabindranath Tagore 种树的人&#xff0c;虽然知道他永远…

如何舒适的使用VScode

安装好VScode后通常会很不好用&#xff0c;以下配置可以让你的VScode变得好用许多。 VScode的配置流程 1、设置VScode中文2、下载C/C拓展&#xff0c;使代码可以跳转3、更改编码格式4、设置滚轮缩放5、设置字体6、设置保存自动改变格式7、vscode设置快捷代码8、下载插件并学会…

Java多线程面试重点-1

0. 什么是并发&#xff1f;什么是并行&#xff1f; 并发&#xff1a;把时间分成一段一段&#xff0c;每个线程轮流抢占时间段。 如果时间段非常短&#xff0c;线程切换非常快&#xff0c;被称为伪并行。并行&#xff1a;多个线程可以同时运行。 并发与并行造成的影响&#xff…

ARM32开发--IIC软实现

知不足而奋进 望远山而前行 目录 文章目录 前言 开发流程 GD32F4软件I2C初始化 GD32F4软件I2C引脚功能 写操作 读操作 总结 前言 在嵌入式系统开发中&#xff0c;软件实现的I2C通信协议扮演着至关重要的角色。本文将深入探讨如何在GD32F4系列微控制器上实现软件I2C功能…

深入浅出 Go 语言的 GPM 模型(Go1.21)

引言 在现代软件开发中&#xff0c;有效地利用并发是提高应用性能和响应速度的关键。随着多核处理器的普及&#xff0c;编程语言和框架如何高效、简便地支持并发编程&#xff0c;成为了软件工程师们评估和选择工具时的一个重要考量。在这方面&#xff0c;Go 语言凭借其创新的并…

Python的Pillow(图像处理库)非常详细的学习笔记

Python的Pillow库是一个非常强大的图像处理库。 安装Pillow库&#xff1a; 在终端或命令行中输入以下命令来安装Pillow&#xff1a; pip install pillow 安装后查看是否安装成功以及当前版本 pip show Pillow 升级库&#xff1a; pip install pillow --upgrade 一些基…

u-boot(六) - 详细启动流程

一&#xff0c;u-boot启动第一阶段 1&#xff0c;启动流程 ENTRY(_start) //arch/arm/lib/vectors.S ----b resets //arch/arm/cpu/armv7/start.S --------b save_boot_params ------------b save_boot_params_ret //将cpu的工作模式设置为SVC32模式&#xff08;即管理模式&a…

NodeClub:NodeJS构造开源交流社区

NodeClub&#xff1a; 连接每一个想法&#xff0c;NodeClub让社区更生动- 精选真开源&#xff0c;释放新价值。 概览 NodeClub是一个基于Node.js和MongoDB构建的社区系统&#xff0c;专为开发者和社区爱好者设计。它提供了一套完整的社区功能&#xff0c;包括用户管理、内容发…

Mongodb在UPDATE操作中使用$push向数组中插入数据

学习mongodb&#xff0c;体会mongodb的每一个使用细节&#xff0c;欢迎阅读威赞的文章。这是威赞发布的第69篇mongodb技术文章&#xff0c;欢迎浏览本专栏威赞发布的其他文章。如果您认为我的文章对您有帮助或者解决您的问题&#xff0c;欢迎在文章下面点个赞&#xff0c;或者关…

qt dll编写和调用

dll编写 新建项目 头文件 #ifndef LIB1_H #define LIB1_H#include "lib1_global.h"class LIB1_EXPORT Lib1 { public:Lib1(); };//要导出的函数&#xff0c;使用extern "C"&#xff0c;否则名称改变将找不到函数extern "C" LIB1_EXPORT int ad…

探索未来边界:前沿技术引领新纪元

目录 引言 一、人工智能与深度学习&#xff1a;智慧生活的引擎 1.医疗应用 2.智能家居 3.自动驾驶 二、量子计算&#xff1a;解锁宇宙的密钥 1.量子比特示意图 2.量子计算机实物图 3.分子模拟应用 三、生物技术&#xff1a;生命科学的革新 1.CRISPR-Cas9基因编辑图 2.合成生…

buuctf----warmup_csaw_2016

进来医院先来一套常规检查 啥保护都没,看大佬说基本栈溢出 CT一看 OK cat flag 更喜欢了 40060D 找到地址 get也来了,稳啦! 0x80-0x40 8 根据上道题的exp from pwn import * ghust remote("node5.buuoj.cn",27229) addr 0x40060D payload bA * 0x40 bB*8…

C++设计模式——Bridge桥接模式

一&#xff0c;桥接模式简介 桥接模式是一种结构型设计模式&#xff0c;用于将抽象与实现分离&#xff0c;这里的"抽象"和"实现"都有可能是接口函数或者类。 桥接模式让抽象与实现之间解耦合&#xff0c;使得开发者可以更关注于实现部分&#xff0c;调用…

具有不确定性感知注意机制的肺结节分割和不确定区域预测| 文献速递-深度学习结合医疗影像疾病诊断与病灶分割

Title 题目 Lung Nodule Segmentation and UncertainRegion Prediction With an Uncertainty-Aware Attention Mechanism 具有不确定性感知注意机制的肺结节分割和不确定区域预测 01 文献速递介绍 肺结节分割在肺癌计算机辅助诊断&#xff08;CAD&#xff09;系统中至关重…

java Springboot网上音乐商城(源码+sql+论文)

1.1 研究目的和意义 随着市场经济发展&#xff0c;尤其是我国加入WTO &#xff0c;融入经济全球化潮流&#xff0c;已进入国内外市场经济发展新时期&#xff0c;音乐与市场联系越来越紧密&#xff0c;我国音乐和网上业务也进入新历史发展阶段。为了更好地服务于市场&#xff0…

不想搭集群,直接用spark

为了完成布置的作业&#xff0c;需要用到spark的本地模式&#xff0c;根本用不到集群&#xff0c;就不想搭建虚拟机&#xff0c;hadoop集群啥的&#xff0c;很繁琐&#xff0c;最后写作业还用不到集群&#xff08;感觉搭建集群对于我完成作业来说没有什么意义&#xff09;&…

Cisco Packet Tracer实验(二)

二、用交换机构建 LAN 构建物件如下&#xff1a; 四个PC 两个交换机 一个Multi Switch多功能拓展控制器 连线必须是这个直线&#xff01;&#xff01;&#xff01;不是虚线 最后实现效果如下&#xff1a; 全部的线是绿的&#xff0c;就表示是通的。 尝试一下&#xff0c;看PC…

SolidWorks对设计电脑硬件配置要求是怎么样的

SolidWorks&#xff0c;作为达索系统&#xff08;Dassault Systemes&#xff09;旗下的子公司&#xff0c;一直以其出色的机械设计软件解决方案而著称。它是基于Parasolid内核开发&#xff0c;是单核三维设计软件&#xff0c;面上使用比较多的版本有SolidWorks2022、SolidWorks…