首页 > 解决方案 > Python lambda 捕获外部变量

问题描述

考虑以下示例:

test = 123
f = lambda x,test=test: print(x, test)
del test
f('hello')

印刷

hello 123

通过捕获 lambda 定义中的变量,似乎保留了原始变量。

当您还可以使用一个简单的对象来存储相同的数据时,是否可以使用lambda

class Test:
    def __init__(self, some_data):
        self.some_data = some_data

    def f(self, x):
        print(x, self.some_data)

t = Test('123')
t.f('hello')

标签: pythonpython-3.xlambda

解决方案


通过捕获 lambda 定义中的变量,似乎保留了原始变量。

因为您将其设置为testlambda 参数的默认值,并且 Python 仅在创建函数时评估参数默认值一次。lambdaFWIW,这与关键字的使用无关-lambda只是语法糖,你会得到与“成熟”功能完全相同的结果,即:

test = 123
def f(x, test=test):
    print(x, test)
test = 456
f('hello')

当您还可以使用一个简单的对象来存储相同的数据时,是否可以使用 lambda?

橘子和苹果,真的。函数并不是用来“存储”任何东西,而是用来执行一些计算。它可以通过参数默认值或通过闭包捕获一些值,虽然对于某些用例非常有用,但并不意味着可以替代适当的对象或集合。所以答案是:取决于你想用这些值和你的功能做什么。

注意:从技术上讲,您在这里所做的是(几乎)所谓的“部分应用程序”(您只需要重命名Test.f并在第二个示例中Test.__call__使用t("hello")))。函数的部分应用是一种机制,通过该机制,当使用 N - x (x < N) 参数调用具有 N 个参数的函数时,返回一个具有 Nx 参数的函数,当使用缺少的参数调用该函数时,将返回原始函数,即:

def foo(a, b=None):
   if b is None:
       return lambda b, a=a: foo(b, a)
   return a + b

# here, `f` is a partial application of function `foo` to `1`
f = foo(1)
print(f)
f(2)

在这种情况下,我们使用闭包来捕获a,在函数式编程传统中——“部分应用程序”也主要是 FWIW 的函数式编程概念。现在,虽然它确实支持一些 FP 特性和习语,但 Python 首先是一种 OO 语言,并且由于闭包是对象的 FP 等价物(闭包是一种将状态和行为封装在一起的方法),实现部分应用程序也很有意义作为适当的类,可以使用“ad hoc”专用对象(您的Test类还有Method对象),或者使用更通用的“部分”类 - 它已经存在于标准库中functools.partial


推荐阅读