python函数扩展

news/2025/4/1 19:43:53/文章来源:https://www.cnblogs.com/rdcamelot/p/18799045

1. lambda函数

用于创建匿名函数,可以作为排序函数中的自定义排序规则,或者作为高阶函数的参数

例如:
按照元组的第二个元素进行排序

numbers=[(1,2),(3,1),(5,4)]
numbers.sort(key=lambda x:x[1])

和map函数一起使用,实现对可迭代对象的操作

numbers=[1,2,3,4,5]
sq=list(map(lambda x:x**2,numbers))

2. 函数装饰器

通过装饰器可以扩展或者修改函数的行为
例如:

def log(func):def wrapper(*args, **kwargs):print(f"调用 {func.__name__} 函数")result = func(*args, **kwargs)print(f"{func.__name__} 函数执行完毕")return resultreturn wrapper@log
def add(x, y):print x + yreturn x + yresult = add(3, 5)

该代码实现了一个用于记录函数的调用和执行情况的装饰器
其中log是一个装饰器函数,接受一个函数func作为参数
直观上理解,在后续定义函数add时,在声明语句前有一个@log,表明log时一个装饰器同时add作为log的函数参数
在装饰器内部定义了一个wrapper函数,具体实现了打印被装饰函数执行前后的日志信息
执行该代码,将会输出

调用 add 函数
8
add 函数执行完毕

注意到wrapper函数中有两个参数*args和**kwargs
这两个参数是通过被修饰函数(如这里的add)传入的参数自动捕获的,作用是接受被修饰参数函数的所有参数,并原样传递给原函数(func)
在上面这个例子中3和5是位置参数,因此args=(3,5),而kwargs={},因为没有关键字参数

3. python函数的参数

python函数的参数可以分为

参数类型 语法 作用
位置参数 def f(a,b) 按顺序传递,且传入顺序固定
默认参数 def f(a=1) 调用时可省略
可变位置参数 *args 接受任意数量的位置参数,打包为元组
可变关键字参数 **kwargs 接受任意数量的关键字参数,打包为字典
仅关键字参数 *,a 要求a必须以关键字形式传递

可变位置参数和可变关键字参数使得函数编写时的灵活性更强,例如前一小节中的装饰器函数中复制参数并原样传递给原函数
同时*和**还可以用作参数解构
具体来说
*解构可迭代对象为位置参数,例如列表、元组、字符串等,然后将序列元素逐个传给函数
例如

def add(a, b, c):return a + b + cnumbers = [1, 2, 3]
result = add(*numbers)  # 等价于 add(1, 2, 3)
print(result)  # 输出: 6
def greet(first, second):print(f"Hello, {first} and {second}!")names = "Alice,Bob"
greet(*names.split(','))  # 等价于 greet("Alice", "Bob")
# 输出: Hello, Alice and Bob!

类似的,**可以解构字典作为关键字参数

def person_info(name, age, city):print(f"{name}, {age}岁, 来自{city}")data = {"name": "Alice", "age": 25, "city": "北京"}
person_info(**data)  # 等价于 person_info(name="Alice", age=25, city="北京")
# 输出: Alice, 25岁, 来自北京

4. 闭包

def outer_function(x):def inner_function(y):return x + yreturn inner_functionclosure = outer_function(10) # x=10 被闭包记住
result = closure(5)
print(result)  # 输出:15

闭包(Closure)是指一个函数(内部函数)可以访问并记住其外部函数(enclosing function)的变量,即使外部函数已经执行完毕。
闭包的两个关键特点:

  1. 内部函数引用外部函数的变量(inner_function 使用了 outer_function 的 x)。
  2. 外部函数返回内部函数(outer_function 返回 inner_function)。

闭包实现的原理是__closure__属性,换言之,如果如果函数是闭包,func.__closure__ 会自动返回一个包含 cell 对象的元组,每个 cell 存储了外部变量的值。
根据闭包的形式,可以发现我们上面提到的装饰器实际上也是闭包的一种特殊应用

闭包的关键特点同时也是Python如何识别闭包的方式,也就是当函数满足

  1. 嵌套函数:外部函数 (outer_function) 内部定义了另一个函数 (inner_function)。
  2. 内部函数引用外部变量:inner_function 使用了 outer_function 的变量(如 x)。
  3. 外部函数返回内部函数:outer_function 返回 inner_function,使得内部函数可以在外部作用域被调用。

函数被识别为闭包
同时一定程度上,可以理解为把外部函数的调用赋给一个变量时,这个变量相当于是存储了外部函数参数的内部函数实例,下次再调用这个变量的时候就相当于调用了内部函数
于是闭包可以用于实现函数工厂(动态生成函数)

def make_multiplier(n):def multiplier(x):return x * nreturn multiplierdouble = make_multiplier(2)
triple = make_multiplier(3)print(double(5))  # 输出: 10
print(triple(5))  # 输出: 15

但是在循环中创建闭包时,所有闭包可能共享同一个变量(这时需用默认参数或 lambda 绑定当前值)

# 错误示例:所有闭包共享最终的 i
functions = []
for i in range(3):def func():return ifunctions.append(func)
print([f() for f in functions])  # 输出: [2, 2, 2]# 正确做法:用默认参数绑定当前值
functions = []
for i in range(3):def func(i=i):  # 绑定当前 ireturn ifunctions.append(func)
print([f() for f in functions])  # 输出: [0, 1, 2]

5. 生成器

生成器是一种特殊的迭代器,通过 yield 关键字实现逐步生成值,而不是一次性计算所有值
这在处理大数据流或无限序列(如斐波那契数列)时非常高效,因为可以仅在需要的时候进行调用
核心特点:

  1. 每次只在调用next()时才会执行yield后的语句(这个特征也可以记作是惰性计算)
  2. 生成器会记住上次执行的位置和局部变量状态

例如:

def fibonacci():a, b = 0, 1       # 初始化前两个斐波那契数while True:       # 无限循环,生成无限长的序列yield a       # 生成当前值 a,并暂停执行a, b = b, a + b  # 更新 a 和 b 为下一个斐波那契数# 创建生成器对象
fib = fibonacci()# 打印前10个斐波那契数
for _ in range(10):print(next(fib))  # 输出: 0, 1, 1, 2, 3, 5, 8, 13, 21, 34

每次调用next()语句(或者初次执行时),函数都会从之前停止的地方继续运行,直到再次遇到yield语句,执行完yield语句后,代码停止,等待下次触发
除了next()外,也可以用send()进行触发,不同的是send还会想生成器发送值x,将作为yield表达式返回值,也就是可以用一个左值来接受,如

def interactive_gen():print("Start")x = yield "Please send a value"  # 第一次 yield 返回提示,等待 sendprint(f"Received: {x}")yield f"You sent: {x}"gen = interactive_gen()
print(next(gen))          # 输出: "Please send a value"(执行到第一个 yield)
print(gen.send(42))       # 输出: "Received: 42" → "You sent: 42"

不过注意第一次调用时,必须用 next() 或 send(None)(因为首次没有 yield 可以接收值)
对于要使用send()的函数来说yield 既是返回点,也是接收点
通过传输消息,可以实现一般代码所不具有的交互性
例如
协程(通过 send() 实现双向通信)

def coroutine():while True:received = yield  # 接收外部发送的值print(f"Received: {received}")c = coroutine()
next(c)        # 启动协程(执行到第一个 yield)
c.send("Hello")  # 输出: "Received: Hello"

委托生成器(yield from)

def sub_gen():yield 1yield 2def main_gen():yield from sub_gen()  # 委托给 sub_genyield 3for num in main_gen():print(num)  # 输出: 1, 2, 3

通过yield的惰性计算,可以实现对大数据、无限序列等的读取,因为不会因为一直执行而导致死循环或者直接耗尽内存
例如用生成器读取超大文件:

def read_large_file(file_path):with open(file_path, 'r') as file:for line in file:yield line.strip()  # 逐行生成,避免内存溢出# 使用示例
for line in read_large_file("huge_file.txt"):process(line)  # 每次处理一行

yield 本质上实现了一种交互式、分步执行的程序控制方

6.函数式编程

高阶函数

高阶函数是可以将其他函数作为自身函数参数或者返回的函数
例如:

def apply(func, x):return func(x)def square(x):return x ** 2result = apply(square, 5)
map函数

map函数可以将函数应用于可迭代对象的每个元素,并返回结果
例如:

numbers = [1, 2, 3, 4, 5]
squared = map(lambda x: x ** 2, numbers)
reduce函数

一定程度上和map比较相似,都是用于可迭代对象的,但是reduce函数是逐步迭代合并结果,例如实现累加

from functools import reducenumbers = [1, 2, 3, 4]
sum_result = reduce(lambda x, y: x + y, numbers)
print(sum_result)  # 输出: 10
numbers = [1, 2, 3]
sum_with_init = reduce(lambda x, y: x + y, numbers, 10)  # 初始值为10
print(sum_with_init)  # 输出: 16 (10 + 1 + 2 + 3)

可以理解为从可迭代对象中依次取出元素,通过指定的二元函数不断更新累积值,最终返回最后一次计算的结果,也就是y从numbers中取出,然后每次更新x=x+y,最后输出x
累加等功能大部分时候都是使用内置函数更为方便,大家如果想要自定义累加逻辑,例如加权和时,可以考虑使用reduce
例如:

data = [(1, 0.5), (2, 1.5), (3, 2.5)]
total = reduce(lambda acc, (val, weight): acc + val * weight, data, 0)
print(total)  # 输出: 1*0.5 + 2*1.5 + 3*2.5 = 11.0

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

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

相关文章

grpc实现Aop

创建项目服务端:微软官方自带的ASP.NET.Core.gRPC服务项目。 客户端:ASP.NET.Core.WebApi项目。 公共类库:主要为AOP自定义拦截器类。依赖包导入 客户端:Grpc.AspNetCore、Grpc.Core.Api、Grpc.Net.ClientFactory、Grpc.Tools。公共类库:Grpc.Core.Api公共类库项目配置 创…

Win 11 安装百度云同步盘

前言全局说明百度网盘最早出来叫“百度云管家”,可以上传下载东西,后来大概在2012年,百度云同步盘上线,后来将云管家和同步盘放到一起,叫百度云,也就是现在用的这个。下面介绍 如何在 Win11上用百度云同步盘一、说明 1.1 环境: Windows 11 家庭版 23H2 22631.3737二、下载…

C语言打卡学习第7天(2025.3.26)(补发)

![](https://img2024.cnblogs.com/blog/3622651/202503/3622651- 20250329002951976-79699626.jpg)1.换个网站把题简单做了几道 2,把积存的问题好好问了一下,明天“亡羊补牢”:冒泡排序、数组指针简单用法、之前网站的简单题 明天贪一点,起码把原来网站那些题啃了

VGG

VGG 网络LRN(Local Response Normalization)来自于AlexNet现在已经不怎么使用,因为经过很多实验并没有较大的作用 conv的stride为1,padding为1 maxpool的size为2,stride为2感受野叠加 论文中一个比较重要的使用就是感受野的叠加 感受野(Receptive Field)是卷积神经网络中一…

日语声调

日语声调的记忆 方法1方法2方法3日语声调的标记方法 方法1:划线规律1:第1个音 和 第2个音不是同音 规律2:出现降音就不会升回去 规律3:“高-低”在第几个音出现,就是几型 方法2:数字

荧光灯下的“绚烂”

“绚烂”这一可以令人愉悦的词汇,在航空发动机研制过程中,却给人另外的意味。荧光检测荧光检测 荧光检测是一种在零件表面进行的无损检测,可用于检测航空发动机零部件因疲劳、撞击、机加、淬火、锻造、铸造过载等因素造成的各种裂纹、接缝等表面缺陷。 当荧光检测应用在航…

课堂里的人工智能,或者说,狂野西部闯进了教育界

诺米科托博士(Normi Coto, PhD)配图来自 Unsplash 的 Element5 Digital3 月 15 日星期六,我参加了一场名为“人文学科中的 AI”的职业发展工作坊。会场人满为患,坐满了来自弗吉尼亚州中学和高中的英语和历史老师。来自弗吉尼亚大学和朗伍德大学的教授主持了这次工作坊,主题…

LED数码管显示独立按键次数

前言 目标 2个独立按键,按下K1,数码管显示的数字加1 按下K2,数码管显示的数字减1 效果 https://www.bilibili.com/video/BV1aXo9YxEhY原理独立按键,用于控制数字的加减把完整的数字,分成若干数位显示构造一个函数 show_digit(pos,digit) , 可以在指定位置(0<=pos<=7…

Bitcoin部署到openEuler RISC-V

Bitcoin项目源码是用C++写的,我对C++以及它的编译工具又比较熟悉,这次我尝试了在openEuler RISC-V 24.09上面部署Bitcoin。网上编译Bitcoin源码的很多都是以前旧版的,旧版编译是用automake之类的工具,但是在最新版只需要用cmake就行,两者的部署方式不相同,我分别记录一下…

NVIDIA安装程序无法继续

原因 在更新驱动时,手贱,下驱动一半关闭了下载流程。导致下载失败,而且进入不了Geforece 解决方法:官网下载最新版驱动,再尝试。 如果不行,检查Windows更新,更新至最新版本 重启后如果不可行,再关闭杀毒软件,关闭防火墙,再尝试,重启再尝试。 如果还是不行,使用卸载…

锚定碳中和,三重角色重构,运营商的第四次跃迁

「 作为能源消耗大户,运营商在面对碳中和的级终命题时需要转变发展思路、转变角色定位。」5G+AI倒逼运营商基础设施建设大规模提速,运营商要更好的生存发展必须要降本提效,碳中和的大目标则要求运营商在快速发展的同时还要破解能源消耗指数级增长的魔咒——这似乎是一个不可…

SpringBoot整合RabbitMQ--Fanout模式

使用springBoot整合rabbitMQ需要事先导入相关依赖:<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-amqp</artifactId></dependency><dependency><groupId>org.springframework.bo…