如何在Python的lambda表达式中使用with语句

问题描述 投票:0回答:3

我使用的是 Python 3.5.2(用于 MS SQL Server 机器学习服务的版本)。我想要一个

lambda
表达式,使用 with 来避免在元组中重复昂贵的计算。一个最小的例子是

lambda x : 
  with x**2 as x2, x**3 as x3 :
    [ (x2**3)*x3-x3 , x2, (x3-5)**x2 ]

但是,这会返回语法错误。

with
语句如何在
lambda
表达式中使用?

我来自 Wolfram 语言,可以做到这一点。例如

With[{x2 = #^2, x3 = #^3},
  { (x2^3)*x3-x3 , x2, (x3-5)^x2 }
]&

我收集了这些微小计算的集合,这些计算仅在代码的一小部分(在另一个函数内)中需要。我想将它们保留为 lambda 函数来选择和

apply
/
map
基于该函数中的特定条件。

python python-3.x lambda with-statement
3个回答
3
投票

在Python 3.8中,你可以这样写

lambda x: [ (x2 := x**2) * (x3:=x**3) - x3, x2, (x3 - 5) ** x2 ]

但是,这不是很可读。我仍然会使用

def
语句来定义命名函数,如 https://stackoverflow.com/a/57976808/1126841.

所示

(也许 Python 的未来版本会找到一种方法来支持函数式 let 表达式,例如

let x2 := x**2, x3 := x**3 in (x2*x3 - x3, x2, (x3-5) ** x2)

但我不会屏住呼吸。这确实需要关键字的可读性,并且对于引入新关键字或重载现有关键字存在强烈的阻力(我承认这是有充分理由的)。)


1
投票

在Python中,拼写为:

def fun1(x):
    x2 = x**2
    x3 = x**3 
    return [(x2**3) * x3 - x3 , x2, (x3 - 5) ** x2]

编辑

还有几点...

首先:有人在评论中提到您可以缓存计算结果以提高性能。这确实是一种常见的模式,通常称为记忆化,在 Python 中很容易实现。请注意,这仅适用于纯函数,并且当然只有在使用相同参数重复调用记忆函数时才有用。

第二点,你提到:

我采取了这条路线并在函数内定义了迷你函数。

你要知道,在Python中,

def
是一个可执行语句,它在执行时创建一个新的
function
对象(是的,Python函数是对象——实际上Python中的一切都是对象)。

这意味着“顶级”函数(在模块顶层定义的函数)在当前进程中首次导入模块时创建一次,但每次外部函数都会重新创建内部(嵌套)函数(封闭的)函数被调用。

此外,Python 函数是闭包,因此嵌套函数可以捕获外部函数的环境(这是在 Python 中使用嵌套函数的主要原因(而且仅就我而言))。

这意味着您可以使用内部函数作为另一种方式来缓存一些预先计算的值并使它们可用于一组函数,即:

def outer(x, y):
    x2 = x ** 2
    x3 = x ** 3

    def func1():
        return [(x2**3) * x3 - x3 , x2, (x3 - 5) ** x2]

    def func2(z):
        # dummy example
        return (x2**y) + (y - x3 ** z)

    # etc

    results = [func2(i) for i in func1()]
    return results

另一方面,如果您的“辅助”函数不依赖于它们的封闭范围,那么在外部函数中定义它们所得到的唯一好处就是每次外部函数一次又一次地创建相同函数的开销叫做。如果每个进程只调用外部函数一次或两次,这当然不是问题,但如果在紧密循环中调用它,开销很快就会成为问题。


0
投票

在 Python 实现中,lambda 表达式必须是可计算的,即可以传递到

eval()
函数中的内容。在 Python 中,并非所有东西都是可评估的。例如,赋值操作 (
a=3
) 是不可评估的,函数调用始终是可评估的(即使函数不返回任何内容,即,它评估为
None
)。因此,由于
with
语句不可评估(即,它不会评估任何内容),因此
eval()
lambda
都不接受它。

作为解决方法,您可以在 lambda 表达式中使用

exec()
,因为根据定义它的计算结果为 None。

在实践中,在 lambda 中使用

with
语句的唯一用处是代码简洁性,这是衡量程序员专业水平的一个重要方面。为了完成同样的任务,新手程序员需要几十行、数百个字符的代码,而专家程序员只需要一行代码中的十几个字符。例如,您可以使用 1 行代码来定义保存 JSON 配置文件的函数,

save_config = lambda obj: exec("with open('.config.json','w') as fp: json.dump(obj, fp, indent=1)")

关于OP的示例,他的目的是避免一遍又一遍地重新计算

x**2
x**3
,因为它可能在目标表达式中出现多次。因此,您需要赋值运算符来预先计算
x2
x3
,但赋值运算符不可计算。所以,这里的技巧是使用括号内
for
循环并使用单项 :

>>> L=lambda x:[[ (x2**3)*x3-x3 , x2, (x3-5)**x2 ] for x2 in [x**2] for x3 in [x**3]][0]
>>> L(1.5)
[35.068359375, 2.25, (2.1081673071098876+2.1081673071098863j)]
© www.soinside.com 2019 - 2024. All rights reserved.