简体   繁体   English

在python中关闭。 我可以在函数的本地上下文中进行闭包吗?

[英]Closure in python. Can I make closure on local context of function?

In javascript I can write function with closure like this 在javascript中我可以像这样用闭包写函数

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

And then use it 然后使用它

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

Can I perform the same in Python (if it depends with different version let me know) ? 我可以在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

It's just a sample. 这只是一个样本。 I want know about closure in Python. 我想知道Python中的闭包。

Python 3 introduced this kind of scoping behavior with PEP 3104 and the nonlocal statement: 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

Other than that, in previous versions, closures do exist, but you have only a read-only access. 除此之外,在以前的版本中,闭包确实存在,但您只有只读访问权限。 So changing x will not work. 所以改变x行不通的。 What you can do however is use a mutable object, like a list, and change that one: 但是你可以做的是使用一个可变对象,比如一个列表,并改变它:

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

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

As you can make any kind of object callable, you can also do something more fancy by defining your own type that has a __call__ method: 由于您可以使任何类型的对象可调用,您还可以通过定义具有__call__方法的自己的类型来做更多花哨的事情:

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

>>> f = UniqueId()
>>> f()
0
>>> f()
1

If all you want is a unique ID, just use the following: 如果你想要的只是一个唯一的ID,只需使用以下内容:

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

id = next(uniqueID)

You can rewrite this with a closure (as poke mentions in his answer ), if you wish to: 你可以用一个闭包重写这个(如他的答案中提到的那样 ),如果你想:

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

uniqueID = getUniqueIDfunction()
id = uniqueID()

This has the caveat that it only works in Python 3+. 这有一点需要注意,它只适用于Python 3+。 For Python 2, you can simulate this behavior by attaching the value x to a class. 对于Python 2,您可以通过将值x附加到类来模拟此行为。

This works, but doesn't do exactly what you want: 这有效,但并不能完全符合您的要求:

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

Because the integer datatype is immutable. 因为整数数据类型是不可变的。 If instead you use a mutable datatype: 相反,如果您使用可变数据类型:

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

Another more complicated example from my own usage: 我自己使用的另一个更复杂的例子:

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

If you want to explicitly specify that something is a closure variable, not a local or global, you use the nonlocal statement. 如果要显式指定某些内容是闭包变量,而不是本地或全局变量,则使用nonlocal语句。 So: 所以:

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

In Python 2.x, there is no nonlocal statement. 在Python 2.x中,没有nonlocal语句。 Your best bet is to upgrade to a modern version of the language. 您最好的选择是升级到该语言的现代版本。 If you can't do that, there are ways to fake it, which are explained in the FAQ, and in PEP 3104 (which introduced nonlocal ). 如果你不能这样做,有办法伪造它,这在常见问题解答和PEP 3104 (引入nonlocal )中有解释。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM