2

在javascript中,我可以像这样编写带有闭包的函数

function getUniqueIDfunction() { 
    var id = 0;                          
    return function() { return id++; }; 
};

然后使用它

uniqueID = getUniqueIDfunction();
uniqueID(); //return 0
uniqueID(); //return 1
...

我可以在 Python 中执行相同的操作吗(如果它取决于不同的版本,请告诉我)?

def getUniqueIDfunction():
    x = -1
    def foo():
        #And I know that it doesn't work with row bellow and without it    
        #global x  
        x += 1
        return x
    return foo

这只是一个样本。我想知道 Python 中的闭包。

4

4 回答 4

5

Python 3 在PEP 3104nonlocal语句中引入了这种作用域行为:

>>> def uniqueId ():
        x = -1
        def inner ():
            nonlocal x
            x += 1
            return x
        return inner

>>> f = uniqueId()
>>> f()
0
>>> f()
1
>>> f()
2

除此之外,在以前的版本中,确实存在闭包,但您只有只读访问权限。所以改变是x行不通的。但是,您可以做的是使用可变对象,例如列表,并更改该对象:

>>> def uniqueId ():
        x = [-1]
        def inner ():
            x[0] += 1
            return x[0]
        return inner

>>> f = uniqueId()
>>> f()
0
>>> f()
1

由于您可以使任何类型的对象可调用,您还可以通过定义自己的具有__call__方法的类型来做一些更花哨的事情:

>>> class UniqueId:
        def __init__ (self):
            self.x = -1
        def __call__ (self):
            self.x += 1
            return self.x

>>> f = UniqueId()
>>> f()
0
>>> f()
1
于 2013-11-05T21:35:13.363 回答
2

如果您想要的只是一个唯一的 ID,只需使用以下内容:

def uniqueID():
    x = 0
    while True:
        yield x  
        x += 1

id = next(uniqueID)

如果您希望

def getUniqueIDfunction():
    x = -1
    def uniqueID():
        nonlocal x
        x += 1
        return x
    return uniqueID

uniqueID = getUniqueIDfunction()
id = uniqueID()

需要注意的是,它仅适用于 Python 3+。对于 Python 2,您可以通过将值附加x到类来模拟此行为。

于 2013-11-05T21:28:41.120 回答
2

这有效,但并不完全符合您的要求:

def getUniqueIDfunction():
    x = -1
    def foo(x=x):
        x += 1
        return x
    return foo
f() # returns 0
f() # returns 0 again!

因为整数数据类型是不可变的。相反,如果您使用可变数据类型:

def counter():
    x = [0]
    def enc():
        x[0] = x[0] + 1
        return x[0]
    return enc
f = counter()
f() # returns 1
f() # returns 2
f() # returns 3

我自己使用的另一个更复杂的例子:

def enumerate_dupes_in_column():
    '''
    provides a dict for counting in the namespace and a function for the
    operation, thus avoiding global variable naming
    '''
    countdict = {}
    def countfunction(arg):
        countdict[arg] = countdict.get(arg, 0) + 1
        if countdict[arg] == 1: 
            return arg
        else: 
            return arg + ', ' + str(countdict[arg])
    return countfunction

f = enumerate_dupes_in_column()
f('foo') # returns foo
f('bar') # returns bar
f('foo') # returns foo, 2
于 2013-11-05T21:36:04.417 回答
1

如果您想明确指定某物是闭包变量,而不是局部或全局变量,请使用该nonlocal语句。所以:

def foo():
    nonlocal x  
    x += 1
    return x

在 Python 2.x 中,没有nonlocal声明。您最好的选择是升级到该语言的现代版本。如果你不能这样做,有办法伪造它,常见问题解答和PEP 3104(介绍了nonlocal)中对此进行了解释。

于 2013-11-05T21:33:28.817 回答