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、下载插件并学会…

MongoDB中UPDATE操作$pullAll

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

Java多线程面试重点-1

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

ARM32开发--IIC软实现

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

Springboot配置websocket,https使用 WebSocket 连接

Springboot配置websocket&#xff0c;https使用 WebSocket 连接 提示&#xff1a;本文简单介绍websocket与http的区别及如何在项目中使用websocket&#xff0c;以springboot项目为例 一、http协议与websocket协议区别 WebSocket 一种在单个TCP连接上进行全双工通信的协议。W…

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

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

动态规划算法设计步骤

1. 定义状态&#xff08;构建记忆表&#xff09;&#xff1a; 首先&#xff0c;需要确定问题的状态。状态可以表示为一个包含所有可能决策的变量的集合。例如&#xff0c;对于一个背包问题&#xff0c;状态可以表示为一个包含所有物品和它们的重量的数组。 2. 初始化&#xff…

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

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

探索Ubuntu:从入门到精通

目录 一、什么是Ubuntu? 1.1 Ubuntu的定义和背景 1.2 Ubuntu的特点 二、安装Ubuntu 2.1 下载Ubuntu安装镜像 2.2 制作启动盘 2.3 安装Ubuntu 三、初步设置和基本操作 3.1 系统更新 3.2 安装必要软件 3.3 设置和管理用户账户 四、文件和目录管理 4.1 文件管理器 …

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;或者关…

spark mllib 特征学习笔记 (一)

PySpark MLlib 特征处理详解 PySpark MLlib 提供了丰富的特征处理工具&#xff0c;帮助我们进行特征提取、转换和选择。以下是 PySpark MLlib 中常用的特征处理类及其简要介绍。 1. Binarizer Binarizer 是将连续特征二值化的转换器。 from pyspark.ml.feature import Bina…

Postman接口测试工具:全面解析与应用指南

标题&#xff1a;Postman接口测试工具&#xff1a;全面解析与应用指南 在当今的软件开发领域&#xff0c;接口测试是确保软件质量和稳定性的重要环节。而Postman作为一款广泛使用的接口测试工具&#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…

css引入方式有几种?link和@import有什么区别?

在CSS中&#xff0c;引入外部样式表的方式主要有两种&#xff1a;<link>标签和import规则。 使用<link>标签引入外部样式表&#xff1a; <link rel"stylesheet" href"path/to/style.css">这种方式是在HTML文档的<head>部分或者…

Maven:复制到自定义的目录比如target/libs目录下

拷贝依赖包 mvn dependency:copy-dependencies&#xff0c;默认会拷到项目的 target\dependency 目录&#xff0c;想要复制到自定义的目录比如target/libs目录下&#xff0c;需要在pom.xml文件中添加设置覆盖默认设置&#xff1a; <build> <plugins> <plugin&g…