gpt4 book ai didi

带闭包的 python 计数器

转载 作者:行者123 更新时间:2023-11-28 20:17:55 28 4
gpt4 key购买 nike

我正在尝试在 python 中构建一个具有闭包属性的计数器。以下工作中的代码:

def generate_counter():
CNT = [0]
def add_one():
CNT[0] = CNT[0] + 1
return CNT[0]
return add_one

但是,当我将列表 CNT 更改为 var 时,它不起作用:

def generate_counter1():
x = 0
def add_one():
x = x + 1
return x
return add_one

当我打印一个实例的闭包属性时,我发现第二种情况的__closure__是none:

>>> ct1 = generate_counter()
>>> ct2 = generate_counter1()
>>> print(ct1.__closure__[0])
<cell at 0xb723765c: list object at 0xb724370c>
>>> print(ct2.__closure__)
None

只是想知道为什么外部函数中的索引必须是列表?


感谢您的回答!找到了清楚解释这个问题的文档 https://docs.python.org/3/faq/programming.html#why-am-i-getting-an-unboundlocalerror-when-the-variable-has-a-value

最佳答案

Python 通过查看名称绑定(bind)行为来确定名称的范围;赋值就是这样一种行为(函数参数、导入、for target ...while .. as target 中的目标是其他示例)。您在函数中绑定(bind)的名称被视为本地。查看Naming and Binding section引用文档。

因此第二个示例中的名称 x 是一个本地 变量,因为您直接为其赋值:

x = x + 1

事实上,因为您从来没有给 x 一个局部值,所以当您尝试使用该函数时会得到一个异常;当您尝试阅读时,本地名称是 unbound:

>>> 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

在您的第一个示例中,没有发生此类绑定(bind);您正在更改 CNT内容,但该名称引用的内容没有更改。

如果您使用的是 Python 3,则可以通过使用 nonlocal statement 来覆盖将名称设为本地的决定。 :

def generate_counter2():
x = 0
def add_one():
nonlocal x
x = x + 1
return x
return add_one

通过使 x 成为非局部的,Python 在父上下文中找到它并再次为它创建一个闭包。

>>> 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 中,您只能使用一些技巧,例如使用可变列表对象来规避绑定(bind)规则。另一个技巧是将计数器分配给嵌套函数的属性;同样,这避免了在当前范围内绑定(bind)名称:

def generate_counter3():
def add_one():
add_one.x += 1
return add_one.x
add_one.x = 0
return add_one

关于带闭包的 python 计数器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38693236/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com