在 SML(我在 Python 之前学习的一种函数式编程语言)中,我可以执行以下操作:
val x = 3;
fun f() = x;
f();
>>> 3
val x = 7;
f();
>>> 3
然而,在 Python 中,第一次调用将给出 3,第二次调用将给出 7。
x = 3
def f(): return x
f()
>>> 3
x = 7
f()
>>> 7
如何将变量的值绑定到 Python 中的函数?
您可以使用关键字参数:
x = 3
def f( x=x ):
return x
x = 7
f() # 3
关键字参数是在创建函数时分配的。当函数运行时,会在函数的作用域中查找其他变量。(如果在函数的作用域中找不到它们,python 会在包含函数的作用域中查找变量等)。
你可以这样做:
x = 3
f = lambda y=x: y
f()
>>> 3
x = 7
f()
>>> 3
与 mgilson 和 Neal 一样,最直接的方法是在定义时使用默认参数f
。
一个更大的问题是这里的哲学不匹配。Python 确实有闭包,但它们的操作方式与您对 SML(我不是特别熟悉)或 Haskell 或 Clojure 或其他东西(我都更熟悉)的预期不同。这是因为 Python 处理闭包的方式,也因为它以不同的方式定义匿名函数并允许副作用。
通常,在函数式方法不能很好地工作的地方,在 Python 中你使用一个类,在这种情况下是为了捕获 x 的值。
class F(object):
def __init__(self, x):
self.x = x
def __call__(self):
return self.x
x = 3
f = F(x)
f()
# 3
x = 7
f()
# 3
对于这个例子来说,这种方式太过分了,我显然不会在这里推荐它。但通常在 Python 中,答案是使用一个类。(这是一个严重的过度陈述,我的大脑产生异常的速度比我输入它们的速度要快。但是当你来自功能背景时,我认为这个陈述是一个很好的启发式,因为你正在学习用 Python 处理问题. )
顺便说一句,这也很有趣,这明确了在函数参数定义中捕获变量的隐含作用:它创建了一个函数对象,该对象挂在x
对象创建点的值上。
这个问题似乎是关于如何在创建闭包时捕获(而不是引用)外部变量的值。从这个意义上说,通常的答案是使用默认参数:
def f(x=x):
return x
# or
f = lambda x=x: x
(但是,如果您想要一个带有可变数量参数的函数,这将不起作用)。或者更一般地说(即使在可变参数情况下也可以)但不太漂亮,使用立即执行的显式包装函数:
f = (lambda x: lambda: x)(x)
但是,我只是想指出您的问题的前提是无效的——在 SML 中,您永远不能分配给变量(我不是在谈论修改可变数据结构,例如ref
;我在谈论分配到变量);语言中甚至没有语法可以做到这一点。
您在 SML 代码中所做的是创建一个新范围并在新范围中定义一个具有相同名称的不同x
变量,从而隐藏以前的x
. 您始终可以简单地将第二个变量重命名为不同的名称,并且对程序没有影响。现在,Python 只有函数作用域,而函数内部的代码块没有内部作用域。但是您可以应用相同的解决方案——只需将第二个变量重命名为不同的名称,您就不会遇到这个问题。