【问题标题】:How to use with statement in lambda expression for Python如何在 Python 的 lambda 表达式中使用 with 语句
【发布时间】:2019-09-17 14:21:02
【问题描述】:

我使用的是 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 ]

但是,这会返回语法错误。在lambda 表达式中如何使用with 语句?

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

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

我收集了这些仅在一小部分代码中需要的微小计算(在另一个函数中)。我想将这些作为 lambda 函数来选择和 apply/map 基于该函数中的特定条件。

【问题讨论】:

  • 为什么不使用普通的def
  • 很确定这是不可能的;这不是 lambdas 的设计目的。做一个函数。
  • 一个 Lambda 可以只包含一个 表达式,所以这在定义上是不可能的。
  • 上下文管理器也不是为此而设计的。
  • @khelwood 我有一组微小的计算,这些计算只需要在一小部分代码中(在另一个函数中)。因此,将这些作为 lambda 函数来选择该函数中的特定条件似乎是合理的。

标签: python python-3.x lambda with-statement


【解决方案1】:

在 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)

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

【讨论】:

  • 感谢您的洞察力。如果 SQL Server 将他们的机器学习服务升级到 3.*+,那么我可能会切换到这个实现。 (+1)
【解决方案2】:

在python中,这是拼写:

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

编辑

还有几点...

首先:有人在评论中提到您可以缓存计算结果以提高性能。这确实是一种常见的模式,通常称为记忆化,which is rather easy to implement in Python。请注意,这仅适用于 pure functions,当然只有在使用相同参数重复调用 memoized 函数时才有用。

第二点,你提到:

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

您必须知道,在 Python 中,def 是一个可执行语句,它在执行时会创建一个新的 function 对象(是的,Python 函数是对象 - 实际上 Python 中的所有内容都是对象)。

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

另外,Python functions are closures,因此嵌套函数可以捕获外部函数的环境(这是在 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

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

【讨论】:

  • 那么唯一的方法是为所有这些小计算创建命名函数,然后在数据框列中按名称引用它们?
  • @Edmund 没有名字。您传递函数对象。您当前正在执行lambda: ... 的位置,而是执行fun1。是的,他们必须被命名。
  • 如果您想避免重复昂贵的计算,那么您只需要以某种方式缓存结果,即命名它们以供以后参考。即使在您的示例中,您的逻辑本质上也是在命名它们,只是在不同的上下文中,这不是 Python 的有效语法。
  • 我采取了这条路线,并在函数中定义了迷你函数。如果它们的数量增加,我很可能会将它们拉到一个包裹中。但这暂时有效。谢谢!
  • @Edmund 请注意,在 Python 中 def 是一个可执行语句,因此在调用外部函数时会重新创建内部(嵌套)函数。根据您的用例,这可能(或不会)对性能产生一些影响。
猜你喜欢
  • 1970-01-01
  • 2023-01-25
  • 1970-01-01
  • 1970-01-01
  • 2011-03-19
  • 2019-09-19
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多