首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Python闭包与javascript闭包

Python闭包与javascript闭包
EN

Stack Overflow用户
提问于 2013-08-29 04:04:02
回答 2查看 4.1K关注 0票数 18

以下闭包函数在javascript中运行良好。

代码语言: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做同样的事情。

代码语言:javascript
复制
def generateNextNumber(startNumber):
    current = startNumber
    def tempFunction():
        current += 1
        return current
    return tempFunction

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

我得到以下错误

代码语言:javascript
复制
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

当我在vars()locals()中打印tempFunction时,他们确认current是存在的。

代码语言:javascript
复制
({'current': 10}, {'current': 10})

但是当我像这样修改程序的时候

代码语言:javascript
复制
def generateNextNumber(startNumber):
    current = {"Number" : startNumber}
    def tempFunction():
        current["Number"] += 1
        return current["Number"]
    return tempFunction

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

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2013-08-29 06:05:17

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

使用global声明

代码语言:javascript
复制
def generateNextNumber(startNumber):
    global current
    current= startNumber
    def tempFunction():
        global current
        current += 1
        return current 
    return tempFunction

在某些情况下有效,但在您的情况下,只有一个tempFunction实例可以同时活动。

使用函数属性

代码语言:javascript
复制
def generateNextNumber(startNumber):
    def tempFunction():
        tempFunction.current += 1
        return tempFunction.current
    tempFunction.current= startNumber
    return tempFunction

使用以下事实:函数是对象(因此可以具有属性),它们在声明时被实例化,并且它们成为包围函数(或模块,在这种情况下它们是全局的)的本地函数。这也是因为名称tempFunction是第一次在自己的定义中使用“成员访问”.操作符,因此不假定是本地的。"call“()和"element”[]运算符也会发生类似的情况。后一种情况解释了代码工作的原因。

强制使用非本地名称。

代码语言:javascript
复制
def generateNextNumber(startNumber):
    current= type("OnTheFly",(),{})()
    current.value= startNumber
    def tempFunction():
        current.value += 1
        return current.value
    return tempFunction

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

使用函数对象

代码语言:javascript
复制
def generateNextNumber(startNumber):
    class TempFunction:
        def __call__(self):
            self.current += 1
            return self.current
    tempFunction= TempFunction()
    tempFunction.current= startNumber
    return tempFunction

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

使用nonlocal声明

代码语言:javascript
复制
def generateNextNumber(startNumber):
    current= startNumber
    def tempFunction():
        nonlocal current
        current += 1
        return current
    return tempFunction

就像global的意思.嗯,全局的,nonlocal的意思是“在前面的范围里”。在Python 3和更高版本的Python 2中都是有效的。

使用发电机

代码语言:javascript
复制
def generateNextNumber(current):
    while True :
        current+= 1
        yield current

这可能是处理非局部变量访问的一般问题的最"Pythonic“方式,而是您用来解释它的具体情况。我不能不提这件事。不过,您需要稍加改动就将其命名为:

代码语言:javascript
复制
getNextNumber = generateNextNumber(10)
for i in range(10):
    print (getNextNumber.next())

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

票数 25
EN

Stack Overflow用户

发布于 2013-08-29 04:10:23

Python通过定义函数包含赋值的任何变量都是本地变量来决定函数的局部变量是什么,除非声明为nonlocalglobal。因此,

代码语言:javascript
复制
current += 1

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

代码语言:javascript
复制
current[0] += 1

作为参考,“试图不这样做”可能如下所示:

代码语言:javascript
复制
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
票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/18502095

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档