Python Lambda捕获外部变量

时间:2018-10-08 09:35:45

标签: python python-3.x 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')

2 个答案:

答案 0 :(得分:1)

定义函数或lambda时,一次评估参数的默认参数值。不会在每个呼叫站点进行评估。 (这就是为什么通常不能使用[]作为默认参数,而必须指定None并编写代码以在每次调用该函数时分配一个新鲜列表的原因。)

lambda,函数或类是否合适,实际上取决于周围的代码。通常,如果只有一个操作并且状态不能直接从外部(仅在操作内部)进行更改,则适合使用lambda或函数。

答案 1 :(得分:1)

  

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

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

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

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

桔子和苹果,真的。函数并不是要用来“存储”任何东西,而是要执行一些计算。它可以通过参数defaults或通过闭包捕获某些值的事实,尽管在某些用例中非常有用,但这并不意味着可以替换适当的对象或集合。因此答案是:取决于您要对这些值和函数执行的操作。

NB:从技术上讲,您在这里所做的(几乎)是所谓的“部分应用程序”(您只需将Test.f重命名为Test.__call__并使用t("hello")在第二个示例中))。函数的部分应用是一种机制,通过该机制,N个参数的函数在用N-x(x

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等价(闭包是将状态和行为封装在一起的一种方式),因此实现部分应用程序也很有意义作为适当的类,可以使用“临时”专用对象(您的Test类,也可以使用Method对象),或者使用更通用的“部分”类-which already exists in the stdlib as functools.partial