Python闭包vs javascript closu

2024-10-01 13:40:16 发布

您现在位置:Python中文网/ 问答频道 /正文

下面的闭包函数在javascript中可以正常工作。在

function generateNextNumber(startNumber) {
    var current = startNumber;
    return function(){
        return current += 1;
    }
}

var getNextNumber = generateNextNumber(10);
for (var i = 0; i < 10; i++) {
    console.log(getNextNumber());
}

我试着用Python做同样的事情

^{pr2}$

我得到以下错误

Traceback (most recent call last):
  File "/home/thefourtheye/Desktop/Test1.py", line 10, in <module>
    print (getNextNumber())
  File "/home/thefourtheye/Desktop/Test1.py", line 4, in tempFunction
    current += 1
UnboundLocalError: local variable 'current' referenced before assignment

当我在tempFunction内打印vars()和{}时,它们确认{}存在。在

({'current': 10}, {'current': 10})

但当我把程序修改成这样

def generateNextNumber(startNumber):
    current = {"Number" : startNumber}
    def tempFunction():
        current["Number"] += 1
        return current["Number"]
    return tempFunction

它起作用了。我无法解释为什么这会起作用。谁能解释一下吗?在


Tags: pynumberhomereturnvarfunctioncurrentfile
2条回答

Python通过定义函数包含赋值的任何变量都是局部变量来决定函数的局部变量,除非声明了nonlocal或{}。因此

current += 1

创建一个名为current的局部变量,该变量隐藏非局部变量。如果您使用的是python2,标准的解决方案(除了尽量不这样做之外)是将current变成一个1元素列表并使用

^{pr2}$

作为参考,“尝试不这样做”可能看起来像下面这样:

class Counter(object):
    def __init__(self):
        self.count = 0
    def __call__(self):
        self.count += 1
        return self.count
c = Counter()
c()  # Returns 1
c()  # Returns 2

Python假设函数中的所有变量都是局部变量。这是为了避免意外使用同名的全局变量,或在封闭范围内使用。在某些重要的方面,这种差异是由于在Python中局部变量声明是自动/隐式的,而在JavaScript中则不是(必须使用var)。解决方案:

使用global声明

def generateNextNumber(startNumber):
    global current
    current= startNumber
    def tempFunction():
        global current
        current += 1
        return current 
    return tempFunction

在某些情况下有效,但在您的实例中,tempFunction只能同时处于活动状态。在

使用函数属性

^{pr2}$

使用这样一个事实:函数是对象(因此可以具有属性),它们在声明时被实例化,并且它们成为封闭函数(或模块,在这种情况下,它们实际上是全局的)的局部的。这也是因为名称tempFunction是第一次在它自己的定义中使用“member access”.运算符,因此没有假定为本地名称。“call”()和“element access”[]运算符也会发生类似的情况。后一个例子解释了代码为什么工作。在

强制将名称假定为非本地

def generateNextNumber(startNumber):
    current= type("OnTheFly",(),{})()
    current.value= startNumber
    def tempFunction():
        current.value += 1
        return current.value
    return tempFunction

这已经在上一节中解释过了。通过使用成员访问操作符.,我们说“current已经存在”,因此在封闭范围内搜索它。在这个特定的例子中,我们使用type函数创建一个类,并立即创建它的一个实例(使用第二组parathese)。我们也可以使用列表或字典来代替一般对象。第二种情况是非常常见的解决办法。在

使用函数对象

def generateNextNumber(startNumber):
    class TempFunction:
        def __call__(self):
            self.current += 1
            return self.current
    tempFunction= TempFunction()
    tempFunction.current= startNumber
    return tempFunction

任何类具有调用方法的对象都是函数,因此可以用函数调用运算符()来调用。这与前两起案件极为相关。在

使用nonlocal声明

def generateNextNumber(startNumber):
    current= startNumber
    def tempFunction():
        nonlocal current
        current += 1
        return current
    return tempFunction

以同样的方式,global意味着。。。嗯,global,nonlocal的意思是“在前一个范围内”。在Python3和Python2的更高版本中有效。在

使用发电机

def generateNextNumber(current):
    while True :
        current+= 1
        yield current

这可能是解决非局部变量访问的一般问题的最“python”方法,而是您用来解释它的特定情况。我不能不提一下就结束了。不过,你需要稍微改变一下:

getNextNumber = generateNextNumber(10)
for i in range(10):
    print (getNextNumber.next())

当驱动for时,对next()的调用是隐式的(但是生成器不能像我的示例中那样是无限的)。在

相关问题 更多 >