带有关闭的python计数器 [英] python counter with closure
问题描述
我正在尝试使用闭包属性在python中建立一个计数器。以下代码中的代码:
I'm trying to build a counter in python with the property of closure. The code in the following works:
def generate_counter():
CNT = [0]
def add_one():
CNT[0] = CNT[0] + 1
return CNT[0]
return add_one
但是,当我将列表CNT更改为var时,它不起作用:
However when I change the list CNT to a var, it did not work:
def generate_counter1():
x = 0
def add_one():
x = x + 1
return x
return add_one
当我打印实例的闭包属性时,我发现了 __ closure __
第二种情况是没有:
when I print the closure property of an instance, I found the __closure__
of the second case is none:
>>> ct1 = generate_counter()
>>> ct2 = generate_counter1()
>>> print(ct1.__closure__[0])
<cell at 0xb723765c: list object at 0xb724370c>
>>> print(ct2.__closure__)
None
只是想知道为什么外部函数的索引必须是列表吗?
Just wondering why the index in outer function has to be a list?
感谢您的回答!找到可以清楚解释此问题的文档
https://docs.python.org/3/faq/programming.html#why-am-i-getting-an-unboundlocalerror-when-the-variable -has-a-value
Thanks for the answers! Found the docs which clearly explained this problem https://docs.python.org/3/faq/programming.html#why-am-i-getting-an-unboundlocalerror-when-the-variable-has-a-value
推荐答案
Python通过查看名称绑定行为来确定名称的范围;赋值就是这样一种行为(函数参数,导入,中的目标...
或中的目标,而..作为目标
是其他示例)。您在函数中绑定的名称被视为 local 。请参见 命名和绑定部分
Python determines the scope of a name by looking at name binding behaviour; assignment is one such behaviour (function parameters, importing, the target in for target ...
or while .. as target
are other examples). A name you bind to in a function is considered local. See the Naming and Binding section of the reference documentation.
因此,第二个示例中的名称 x
是 local 变量,因为您直接分配给它:
So the name x
in your second example is a local variable, because you assigned directly to it:
x = x + 1
实际上,因为您从未给 x
赋予局部值,所以您会得到当您尝试使用该功能时发生异常;尝试阅读时,本地名称为 unbound 。
In fact, because you never gave that x
a local value, you'll get an exception when you try to use that function; the local name is unbound when you try to read it:
>>> generate_counter1()()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 4, in add_one
UnboundLocalError: local variable 'x' referenced before assignment
$之前引用了本地变量'x' b
$ b
在您的第一个示例中,没有这种绑定发生;您而是更改了 CNT
的内容,该名称引用的内容未更改。
In your first example no such binding takes place; you are instead altering the contents of CNT
, what that name references is not altered.
如果您使用的是Python 3,则可以使用 非本地
语句:
If you are using Python 3, you can override the decision to make a name local, by using a nonlocal
statement:
def generate_counter2():
x = 0
def add_one():
nonlocal x
x = x + 1
return x
return add_one
通过将 x
设为非本地,Python会找到它
By making x
non-local, Python finds it in the parent context and creates a closure for it again.
>>> def generate_counter2():
... x = 0
... def add_one():
... nonlocal x
... x = x + 1
... return x
... return add_one
...
>>> generate_counter2().__closure__
(<cell at 0x1078c62e8: int object at 0x1072c8070>,)
nonlocal
是Python 3中的新功能;在Python 2中,您只能使用一些技巧,例如使用可变列表对象来规避绑定规则。另一个技巧是将计数器分配给嵌套函数的属性。再次,这避免了在当前范围内绑定名称:
nonlocal
is new in Python 3; in Python 2 you are limited to tricks like using a mutable list object to evade the binding rule. Another trick would be to assign the counter to an attribute of the nested function; again, this avoids binding a name in the current scope:
def generate_counter3():
def add_one():
add_one.x += 1
return add_one.x
add_one.x = 0
return add_one
这篇关于带有关闭的python计数器的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!