python lambda表达式及用法_Python:lambda表达式和yield关键字理解与使用讲解

一、lambda表达式

1.1、lambda表达式理解

lambda的主体是一个表达式,而不是一个代码块,仅仅能在lambda表达式中封装有限的逻辑进去。如果要通俗的理解lambda表达式,可以结合C/C++中的逻辑宏定义和内联函数概念,lambda表达式通俗的讲是起到一个函数速写的作用,并且允许在lambda代码块内嵌入一个函数的定义。

1.2、lambda表达式使用

1.2.1 简单的求和

f = lambda x, y: x + y

print(f(1, 2))

# 输出: 3

1.2.2 lambda表达式实现n的阶乘

from functools import reduce

n = 5

out = reduce(lambda x, y : x*y, range(1, n+1))

print(out)

# 输出: 120

1.2.3 函数中使用lambda

def foo(x):

return lambda y: x + y

a = foo(2)

print(a(2))

# 输出: 4

1.2.4 把函数直接写成lambda形式

foo = lambda x: lambda y: x + y# 第一个lambda理解为用于foo函数传入x参数,第二个lambda相当于2.2中返回值里的lambda表达式

a = foo(3)

print(a(2))

# 输出: 5

1.3、通常使用lambda表达式的地方

通常会在调用接受函数作为参数的函数(或者类)时使用lambda表达式,比如python内置的sorted函数可接受一个函数作为它的key参数,这个key函数用于在决定条目排序顺序时计算比较键的值,比如:

a = ['1', '3', '5', '2', '9', '7']

print(sorted(a, key=lambda s: s.casefold()))

# 输出: ['1', '2', '3', '5', '7', '9']

sorted函数并不是lambda表达式的唯一用法,但却是最普遍的一个。

1.4、lambda使用问题(利弊及滥用问题)

二、yield关键字

2.1、yield关键字的理解与使用

yield关键字作用的通俗理解是:定义生成器(generator)时常用的一个带有return作用的关键字,当一个函数带有yield关键字,那么这个函数已经不再是通俗意义上的函数,它是一个生成器(带yield关键字的函数才是真正的迭代器)。

下面通过小程序的解读来说明yield关键字的作用与用法:

def foo():

print('hello')

while True:

r = yield 1

print('r: ', r)

a = foo()

print(next(a))

print('-'*6)

print(next(a))

输出如下

hello

1

------

r: None

1

解释:

1、程序开始执行以后,因为foo函数中有yield关键字,所以foo函数并不会真的执行,而是先得到一个生成器(相当于一个对象);

2、直到调用next方法,foo函数正式开始执行,先执行foo函数中的print方法,然后进入while循环;

3、程序遇到yield关键字,然后把yield想想成return,return了一个1之后,程序停止,并没有执行赋值给r操作,此时next(g)语句执行完成,所以输出的前两行(第一个是while上面的print的结果,第二个是return出的结果)是执行print(next(a))的结果;

4、打印分割线

5、又开始执行下面的print(next(a)),这个时候和上面那个差不多,不过不同的是,这个时候是从刚才那个next程序停止的地方开始执行的,也就是要执行r的赋值操作,这时候要注意,这个时候赋值操作的右边是没有值的(因为刚才那个是return出去了,并没有给赋值操作的左边传参数),所以这个时候r赋值是None,所以接着下面的输出就是r: None;

6、程序会继续在while里执行,又一次碰到yield,这个时候同样return 出1,然后程序停止,print函数输出的1就是这次return出的1。

说明:这里的next函数是通过yield关键字得到的生成器(前面我们说了这个生成器相当于一个对象)自带的一个方法,相当于“下一步”,next开始的地方是接着上一个next停止的地方执行的,所以调用next的时候,生成器并不会从foo函数的开始执行,而是从上一次停止的地方开始执行,在遇到下一个yield的时候结束。

下面介绍一下生成器对象中的另一个函数:send函数

def foo():

print('hello')

while True:

r = yield 1

print('r: ', r)

a = foo()

print(next(a))

print('-'*6)

print(a.send(2))

输出如下

hello

1

------

r: 2

1

send函数的概念:就上面的程序而言:send是发送一个参数给r的,因为上面讲到,return的时候,并没有把1赋值给r,下次执行的时候只好继续执行赋值操作,只好赋值为None了,而如果用send的话,开始执行的时候,先接着上一次(return 1之后)执行,先把2赋值给了r,然后执行next的作用,遇见下一个的yield,return出结果后结束。

2.2 为什么使用包含yield的生成器

为什么用这个生成器,是因为如果用List的话,会占用更大的空间,比如取0~1000,一般我们可能这样写:

for n in range(1000):

a = n

这个时候range(1000)段语句就默认生成一个含有1000个数的list(也就相当于C++中定义数组时固定大小)不管你是否使用这个list,它都在那里,占用内存,直到python解释器自动回收。然而使用yield组合便相当于一个动态的数据定义过程,如下:

def foo(num):

while num < 10:

num = num + 1

yield num

for n in foo(0):

print(n, end=' ')

print('')

'''

输出如下:

1 2 3 4 5 6 7 8 9 10

'''

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在信号处理领域,DOA(Direction of Arrival)估计是一项关键技术,主要用于确定多个信号源到达接收阵列的方向。本文将详细探讨三种ESPRIT(Estimation of Signal Parameters via Rotational Invariance Techniques)算法在DOA估计中的实现,以及它们在MATLAB环境中的具体应用。 ESPRIT算法是由Paul Kailath等人于1986年提出的,其核心思想是利用阵列数据的旋转不变性来估计信号源的角度。这种算法相比传统的 MUSIC(Multiple Signal Classification)算法具有较低的计算复杂度,且无需进行特征值分解,因此在实际应用中颇具优势。 1. 普通ESPRIT算法 普通ESPRIT算法分为两个主要步骤:构造等效旋转不变系统和估计角度。通过空间平移(如延时)构建两个子阵列,使得它们之间的关系具有旋转不变性。然后,通过对子阵列数据进行最小二乘拟合,可以得到信号源的角频率估计,进一步转换为DOA估计。 2. 常规ESPRIT算法实现 在描述中提到的`common_esprit_method1.m`和`common_esprit_method2.m`是两种不同的普通ESPRIT算法实现。它们可能在实现细节上略有差异,比如选择子阵列的方式、参数估计的策略等。MATLAB代码通常会包含预处理步骤(如数据归一化)、子阵列构造、旋转不变性矩阵的建立、最小二乘估计等部分。通过运行这两个文件,可以比较它们在估计精度和计算效率上的异同。 3. TLS_ESPRIT算法 TLS(Total Least Squares)ESPRIT是对普通ESPRIT的优化,它考虑了数据噪声的影响,提高了估计的稳健性。在TLS_ESPRIT算法中,不假设数据噪声是高斯白噪声,而是采用总最小二乘准则来拟合数据。这使得算法在噪声环境下表现更优。`TLS_esprit.m`文件应该包含了TLS_ESPRIT算法的完整实现,包括TLS估计的步骤和旋转不变性矩阵的改进处理。 在实际应用中,选择合适的ESPRIT变体取决于系统条件,例如噪声水平、信号质量以及计算资源。通过MATLAB实现,研究者和工程师可以方便地比较不同算法的效果,并根据需要进行调整和优化。同时,这些代码也为教学和学习DOA估计提供了一个直观的平台,有助于深入理解ESPRIT算法的工作原理。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值