【JAVA工程师从0开始学AI】,第四步:闭包与高阶函数——用Python的“魔法函数“重构Java思维
副标题:当严谨的Java遇上"七十二变"的Python函数式编程
历经变量战争、语法迷雾、函数对决,此刻我们将踏入Python最迷人的领域——函数式编程。当Java工程师还在用接口和匿名类实现回调时,Python的闭包已化身"智能机器人",带着"记忆传承"的能力自由穿梭于代码之间。这里没有类的枷锁,函数既是武器又是盾牌,高阶函数组合出的"代码万花筒",正是AI数据处理、模型训练的核心密码。本文将用Java程序员熟悉的战场,揭开Python函数式编程的降维打击!
先来看一段Python的代码全貌【套娃函数】
def make_function(parity): # ① 母函数# 根据参数生成不同过滤规则if parity == 'even':matches_parity = lambda x: x % 2 == 0 # ② 小工具Aelif parity == 'odd':matches_parity = lambda x: x % 2 != 0 # 小工具Belse:raise AttributeError("参数不对!") # ③ 防呆设计# 核心功能藏在子函数里def get_by_parity(numbers): # ④ 子函数return [num for num in numbers if matches_parity(num)] # 关键魔法在这里return get_by_parity # ⑤ 把子函数当礼物送出去
下面逐行解析,上面每一行Python代码是什么意思
① 母函数开工
make_function('odd')被调用时,就像开了一家定制化工厂- 参数
parity是订单要求(要奇数还是偶数过滤器)
② 流水线选择
if parity == 'even':matches_parity = lambda x: x%2 ==0 # 造偶数检测器
elif parity == 'odd':matches_parity = lambda x: x%2 !=0 # 造奇数检测器
- 根据订单选择生产线(
lambda就是迷你检测装置) - 相当于给后续流程安装不同的"筛子"
③ 容错机制
else:raise AttributeError("Unknown Parity: "+parity)
- 防止乱传参数(比如传了个"cat"进来)
- 相当于工厂质检员,发现不合格订单直接拒收
④ 核心生产线
def get_by_parity(numbers):return [num for num in numbers if matches_parity(num)]
- 这才是真正干活的流水线
matches_parity这个筛子是从母函数拿的(重点!)- 列表推导式就像传送带,逐个检查数字
⑤ 出厂发货
return get_by_parity
- 不返回具体产品,而是返回整条定制化流水线
- 相当于客户拿到的是专属生产机器
闭包魔法揭秘(重点难点)
当执行 get_odds = make_function('odd') 时:
- 母函数执行完毕,按理说内部变量该销毁了
- 但是子函数
get_by_parity记住了当时创建的matches_parity - 就像时间胶囊,把当时的判断条件冻结保存了
Java对比时刻(用你熟悉的领域):
// Java 实现类似闭包(需要用到接口)
interface NumberChecker {boolean check(int x);
}public static NumberChecker makeChecker(String parity) {
if ("odd".equals(parity)) {return x -> x % 2 != 0; // lambda表达式
} else {return x -> x % 2 == 0;
}
}
// 使用时:
NumberChecker oddChecker = makeChecker("odd");
oddChecker.check(5); // true
- Python的闭包更简洁,不用显式定义接口
- Java8的lambda确实和Python的闭包更相似了
实战演示(眼见为实)
# 下单定制奇数过滤器
get_odds = make_function('odd') # 拿到专属流水线# 来料加工
print(get_odds(range(10))) # [1,3,5,7,9] # 再下单一台偶数过滤器
get_evens = make_function('even')
print(get_evens([2,5,8,11])) # [2,8]
关键理解点:
get_odds不是数据,而是一个功能完整的函数- 每次调用
make_function都像开新工厂,生产不同型号的机器
设计哲学(作者想传达的)
- 函数是一等公民:可以当参数传递、当返回值、存在变量里
- 闭包的力量:子函数能记住出生时的环境(母函数的变量)
- Python特色:相比Java的面向对象思维,这里用纯函数式解决更简洁
举个反例(如果用Java思维写Python):
class ParityFilter: # 强行用类实现def __init__(self, parity):self.parity = paritydef filter(self, numbers):if self.parity == 'odd':return [x for x in numbers if x%2 !=0]else:return [x for x in numbers if x%2 ==0]# 使用对比
get_odds = ParityFilter('odd').filter # 类版
vs
get_odds = make_function('odd') # 函数版
- 函数式版本更轻量,不需要定义类
- 符合"能用简单结构就不用复杂封装"的Python哲学
来自Java程序员的灵魂拷问!
如果你作为一个Java程序员,经历过上面的代码,可能就会像我当时学的这段内容的时候,发出灵魂的拷问。
灵魂拷问:这个方法感觉像 “脱裤子放屁”,为什么不把参数一次给全了,然后直接根据判断返回结果?
回答:其实这正是Python的精妙支持也正是理解高阶函数的关键所在。我来用「点外卖」的比喻帮你彻底搞懂这种写法的精妙之处:
场景对比(直接传参 vs 工厂函数)
方案A:每次点单都说明要求(直接传参)
def 做奶茶(原料, 温度, 甜度):if 温度 == '去冰': 处理温度()if 甜度 == '三分糖': 调整甜度()return 成品# 每次点单都要重复说要求
做奶茶(原料, '去冰', '三分糖')
做奶茶(原料, '去冰', '三分糖')
做奶茶(原料, '去冰', '三分糖')
方案B:先定制个人菜单(工厂函数)
def 奶茶工厂(温度, 甜度):def 我的专属奶茶(原料):if 温度 == '去冰': 处理温度()if 甜度 == '三分糖': 调整甜度()return 成品return 我的专属奶茶# 一次设定,终身受用
我的奶茶 = 奶茶工厂('去冰', '三分糖')
我的奶茶(原料)
我的奶茶(原料)
我的奶茶(原料)
为什么方案B更优雅?
- 避免重复劳动(DRY原则)
-
- 就像把常用地址存到外卖APP里,不用每次手动输入
- 在需要多次调用相同配置时,节省大量重复参数
- 关注点分离
-
- 配置阶段:专注设定规则(是奇数还是偶数)
- 执行阶段:专注处理数据(传数字列表就行)
- 函数即服务
# 把功能当乐高积木传递
data_pipeline = [make_function('even'), # 第一道过滤lambda x: [n for n in x if n>5], # 第二道过滤str # 第三道转换
]result = data
for processor in data_pipeline:result = processor(result)
- 延迟执行
-
- 像预先设置好参数的定时任务
- 真正执行的时机可以灵活控制
- 防御性编程
# 在配置阶段就排除错误
try:faulty_filter = make_function('invalid') # 立刻报错
except AttributeError:print("立刻发现配置错误")# 对比直接传参可能在运行时才报错
filter_numbers([1,2,3], 'invalid') # 可能到很晚才出错
实战场景案例
假设我们要处理电商订单:
def 创建订单过滤器(最低金额, 商品类别):def 实际过滤器(订单列表):return [订单 for 订单 in 订单列表if 订单.金额 >= 最低金额and 订单.类别 == 商品类别]return 实际过滤器# 在系统初始化时配置
过滤高价数码订单 = 创建订单过滤器(5000, '数码产品')
过滤食品订单 = 创建订单过滤器(0, '食品')# 在数据处理时直接使用
今日订单 = 获取今日订单()
重点客户订单 = 过滤高价数码订单(今日订单)
促销订单 = 过滤食品订单(今日订单)
什么时候该用这种模式?
| 场景特征 | 适用工厂函数 | 适合直接传参 |
| 需要重复使用相同配置 | ✅ | ❌ |
| 参数需要动态组合 | ✅ | ❌ |
| 配置需要在不同模块间传递 | ✅ | ❌ |
| 只需要单次使用 | ❌ | ✅ |
| 参数组合简单且不变化 | ❌ | ✅ |
回到你的例子(终极解密)
你设想的直接传参版本:
def 直接过滤(numbers, parity):if parity == 'odd':return [x for x in numbers if x%2 !=0]else:return [x for x in numbers if x%2 ==0]
VS 对比一下原文的工厂函数版本:
核心区别在于:当你在一个业务流程中需要多次使用同一种过滤规则时,比如:
# 在数据预处理流程中
数据流 = [原始数据1, 原始数据2, 原始数据3]# 如果用直接传参
清洗后数据 = [直接过滤(数据, 'odd') for 数据 in 数据流
]# 如果用工厂函数
奇数过滤器 = make_function('odd')
清洗后数据 = [奇数过滤器(数据) for 数据 in 数据流]
虽然在这个简单例子中差异不大,但当:
- 过滤逻辑更复杂时(比如需要10个参数)
- 需要跨多个函数传递过滤逻辑时
- 要动态生成不同过滤组合时
工厂函数的优势就会像滚雪球一样越来越大!
最后用一句话总结:这种模式就像函数界的3D打印机——先造模具(工厂函数),然后无限复制成品(闭包函数),比每次手工捏泥人(直接传参)高效得多!
有问题可以发邮件给我:leeborn@qq.com
相关文章:
【JAVA工程师从0开始学AI】,第四步:闭包与高阶函数——用Python的“魔法函数“重构Java思维
副标题:当严谨的Java遇上"七十二变"的Python函数式编程 历经变量战争、语法迷雾、函数对决,此刻我们将踏入Python最迷人的领域——函数式编程。当Java工程师还在用接口和匿名类实现回调时,Python的闭包已化身"智能机器人"…...
算法日记20:SC72最小生成树(prim朴素算法)
一、题目: 二、题解 2.1:朴素prim的步骤解析 O ( n 2 ) O(n^2) O(n2)(n<1e3) 0、假设,我们现在有这样一个有权图 1、我们随便找一个点,作为起点开始构建最小生成树(一般是1号),并且存入intree[]状态数组中…...
玩转SpringCloud Stream
背景及痛点 现如今消息中间件(MQ)在互联网项目中被广泛的应用,特别是大数据行业应用的特别的多,现在市面上也流行这多个消息中间件框架,比如ActiveMQ、RabbitMQ、RocketMQ、Kafka等,这些消息中间件各有各的优劣,但是想…...
嵌入式经常用到串口,如何判断串口数据接收完成?
说起通信,首先想到的肯定是串口,日常中232和485的使用比比皆是,数据的发送、接收是串口通信最基础的内容。这篇文章主要讨论串口接收数据的断帧操作。 空闲中断断帧 一些mcu(如:stm32f103)在出厂时就已经在…...
iOS App的启动与优化
App的启动流程 App启动分为冷启动和热启动 冷启动:从0开始启动App热启动:App已经在内存中,但是后台还挂着,再次点击图标启动App。 一般对App启动的优化都是针对冷启动。 App冷启动可分为三个阶段: dyld:…...
导出指定文件夹下的文件结构 工具模块-Python
python模块代码 import os import json import xml.etree.ElementTree as ET from typing import List, Optional, Dict, Union from pathlib import Path class DirectoryTreeExporter:def __init__(self,root_path: str,output_file: str,fmt: str txt,show_root: boo…...
Leetcode - 周赛436
目录 一、3446. 按对角线进行矩阵排序二、3447. 将元素分配给有约束条件的组三、3448. 统计可以被最后一个数位整除的子字符串数目四、3449. 最大化游戏分数的最小值 一、3446. 按对角线进行矩阵排序 题目链接 本题可以暴力枚举,在确定了每一个对角线的第一个元素…...
【pytest】编写自动化测试用例命名规范README
API_autoTest 项目介绍 1. pytest命名规范 测试文件: 文件名需要以 test_ 开头或者以 _test.py 结尾。例如,test_login.py、user_management_test.py 这样的命名方式,pytest 能够自动识别并将其作为测试文件来执行其中的测试用例。 测试类…...
Compose常用UI组件
Compose常用UI组件 概述Modifier 修饰符常用Modifier修饰符作用域限定Modifier Modifier 实现原理Modifier.Element链的构建链的解析 常用基础组件常用布局组件列表组件 概述 Compose 预置了很多基础组件,如 Button,TextField,TopAppBar等&a…...
斐波那契数列模型:在动态规划的丝绸之路上追寻斐波那契的足迹(上)
文章目录 引言递归与动态规划的对比递归解法的初探动态规划的优雅与高效自顶向下的记忆化搜索自底向上的迭代法 性能分析与比较小结 引言 斐波那契数列,这一数列如同一条无形的丝线,穿越千年时光,悄然延续其魅力。其定义简单而优美ÿ…...
Hackthebox- Season7- Titanic 简记 [Easy]
简记 ip重定向到 http://titanic.htb,先添加hosts 收集子域名 wfuzz -c -u http://titanic.htb/ -w /usr/share/seclists/Discovery/DNS/subdomains-top1million-20000.txt -H Host:FUZZ.titanic.htb --hl 9 ******************************************************** * Wfu…...
Sa-Token 根据官方文档简单实现登录认证的示例
Sa-Token 根据官方文档实现登录鉴权测试 功能实现步骤依赖配置文件启动类创建 controller启动项目测试不用密码登录查看cookie状态 密码登录查看cookie状态 修改token名称 Apipost 测试无 cookie 模式【使用 token】后端将 token 返回到前端修改代码:测试࿱…...
rustdesk编译修改名字
最近,我用Rust重写了一个2W行C代码的linux内核模块。在此记录一点经验。我此前没写过内核模块,认识比较疏浅,有错误欢迎指正。 为什么要重写? 这个模块2W行代码量看起来不多,却在线上时常故障,永远改不完。…...
BS5852英国家具防火安全条款主要包括哪几个方面呢?
什么是BS5852检测? BS5852是英国针对家用家具的强制性安全要求,主要测试家具在受到燃烧香烟和火柴等火源时的可燃性。这个标准通常分为四个部分进行测试,但实际应用中主要测试第一部分和第二部分,包括烟头测试和利用乙炔火焰模拟…...
【运维】源码编译安装cmake
背景: 已经在本地源码编译安装gcc/g,现在源码安装cmake 下载源码 下载地址:CMake - Upgrade Your Software Build System 安装步骤: ./bootstrap --prefix/usr/local/cmake make make install 错误处理 1、提示找不到libmpc.…...
检测网络安全漏洞 工具
实验一的名称为信息收集和漏洞扫描 实验环境:VMware下的kali linux2021和Windows7 32,网络设置均为NAT,这样子两台机器就在一个网络下。攻击的机器为kali,被攻击的机器为Windows 7。 理论知识记录: 1.信息收集的步骤 2.ping命令…...
frameworks 之 Activity添加View
frameworks 之 Activity添加View 1 LaunchActivityItem1.1 Activity 创建1.2 PhoneWindow 创建1.3 DecorView 创建 2 ResumeActivityItem 讲解 Activity加载View的时机和流程 涉及到的类如下 frameworks/base/core/java/android/app/Activity.javaframeworks/base/services/cor…...
UWB技术中的两种调制方式:PPM与PAM
Ultra-Wideband (UWB) 技术以其低功耗、宽频谱和高精度定位的特点,广泛应用于物联网(IoT)、智能家居、资产追踪和无线通信等领域。在UWB中,信号的调制方式对于数据传输的效率和精度起着至关重要的作用。本文将深入探讨UWB中常用的…...
达梦:用户和模式
目录标题 数据库管理系统与用户权限管理**四权分立****用户管理与权限划分****用户管理界面与权限控制****用户创建与管理****实操**1. **默认创建用户与模式**:2. **用户权限和角色分配**:3. **命令行管理用户与角色**:4. 模式也可以创建 **…...
23. AI-大语言模型-DeepSeek
文章目录 前言一、DeepSeek是什么1. 简介2. 产品版本3. 特征4. 地址链接5. 三种访问方式1. 网页端和APP2. DeepSeek API 二、DeepSeek可以做什么1. 应用场景2. 文本生成1. 文本创作2. 摘要与改写3. 结构化生成 3. 自然语言理解与分析1. 语义分析2. 文本分类3. 知识推理 4. 编程…...
Python爬虫实战:研究MechanicalSoup库相关技术
一、MechanicalSoup 库概述 1.1 库简介 MechanicalSoup 是一个 Python 库,专为自动化交互网站而设计。它结合了 requests 的 HTTP 请求能力和 BeautifulSoup 的 HTML 解析能力,提供了直观的 API,让我们可以像人类用户一样浏览网页、填写表单和提交请求。 1.2 主要功能特点…...
论文解读:交大港大上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化学习框架(二)
HoST框架核心实现方法详解 - 论文深度解读(第二部分) 《Learning Humanoid Standing-up Control across Diverse Postures》 系列文章: 论文深度解读 + 算法与代码分析(二) 作者机构: 上海AI Lab, 上海交通大学, 香港大学, 浙江大学, 香港中文大学 论文主题: 人形机器人…...
Java如何权衡是使用无序的数组还是有序的数组
在 Java 中,选择有序数组还是无序数组取决于具体场景的性能需求与操作特点。以下是关键权衡因素及决策指南: ⚖️ 核心权衡维度 维度有序数组无序数组查询性能二分查找 O(log n) ✅线性扫描 O(n) ❌插入/删除需移位维护顺序 O(n) ❌直接操作尾部 O(1) ✅内存开销与无序数组相…...
MODBUS TCP转CANopen 技术赋能高效协同作业
在现代工业自动化领域,MODBUS TCP和CANopen两种通讯协议因其稳定性和高效性被广泛应用于各种设备和系统中。而随着科技的不断进步,这两种通讯协议也正在被逐步融合,形成了一种新型的通讯方式——开疆智能MODBUS TCP转CANopen网关KJ-TCPC-CANP…...
【OSG学习笔记】Day 16: 骨骼动画与蒙皮(osgAnimation)
骨骼动画基础 骨骼动画是 3D 计算机图形中常用的技术,它通过以下两个主要组件实现角色动画。 骨骼系统 (Skeleton):由层级结构的骨头组成,类似于人体骨骼蒙皮 (Mesh Skinning):将模型网格顶点绑定到骨骼上,使骨骼移动…...
【JavaWeb】Docker项目部署
引言 之前学习了Linux操作系统的常见命令,在Linux上安装软件,以及如何在Linux上部署一个单体项目,大多数同学都会有相同的感受,那就是麻烦。 核心体现在三点: 命令太多了,记不住 软件安装包名字复杂&…...
08. C#入门系列【类的基本概念】:开启编程世界的奇妙冒险
C#入门系列【类的基本概念】:开启编程世界的奇妙冒险 嘿,各位编程小白探险家!欢迎来到 C# 的奇幻大陆!今天咱们要深入探索这片大陆上至关重要的 “建筑”—— 类!别害怕,跟着我,保准让你轻松搞…...
STM32标准库-ADC数模转换器
文章目录 一、ADC1.1简介1. 2逐次逼近型ADC1.3ADC框图1.4ADC基本结构1.4.1 信号 “上车点”:输入模块(GPIO、温度、V_REFINT)1.4.2 信号 “调度站”:多路开关1.4.3 信号 “加工厂”:ADC 转换器(规则组 注入…...
结构化文件管理实战:实现目录自动创建与归类
手动操作容易因疲劳或疏忽导致命名错误、路径混乱等问题,进而引发后续程序异常。使用工具进行标准化操作,能有效降低出错概率。 需要快速整理大量文件的技术用户而言,这款工具提供了一种轻便高效的解决方案。程序体积仅有 156KB,…...
Django RBAC项目后端实战 - 03 DRF权限控制实现
项目背景 在上一篇文章中,我们完成了JWT认证系统的集成。本篇文章将实现基于Redis的RBAC权限控制系统,为系统提供细粒度的权限控制。 开发目标 实现基于Redis的权限缓存机制开发DRF权限控制类实现权限管理API配置权限白名单 前置配置 在开始开发权限…...
