Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/354.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 为什么使用正则变量的嵌套函数不能更改外部作用域中的同名变量,而使用列表项的嵌套函数可以更改外部作用域中的同名变量?_Python_Python 3.x - Fatal编程技术网

Python 为什么使用正则变量的嵌套函数不能更改外部作用域中的同名变量,而使用列表项的嵌套函数可以更改外部作用域中的同名变量?

Python 为什么使用正则变量的嵌套函数不能更改外部作用域中的同名变量,而使用列表项的嵌套函数可以更改外部作用域中的同名变量?,python,python-3.x,Python,Python 3.x,为什么第一个示例中使用正则变量的嵌套函数不能更改外部范围中的变量,而第二个示例中使用列表中的项的嵌套函数可以更改外部范围中的变量 我正在从语言设计的角度寻找答案 谢谢 示例一: def make_counter(): count = 0 def counter(): count += 1 return count return counter 例二: def make_counter(): count = [0] def

为什么第一个示例中使用正则变量的嵌套函数不能更改外部范围中的变量,而第二个示例中使用列表中的项的嵌套函数可以更改外部范围中的变量

我正在从语言设计的角度寻找答案

谢谢

示例一:

def make_counter():
    count = 0
    def counter():
        count += 1
        return count
    return counter
例二:

def make_counter():
    count = [0]
    def counter():
        count[0] += 1
        return count[0]
    return counter

这是因为python中的整数是可模的,而列表不是

因此,当您写入count+=1时,这相当于

count = count + 1
value = count[0]
value = value + 1
count[0] = value
这将创建一个新变量,该变量随后是计数器的本地变量,相反,当您写入计数[0]+=1时,这相当于

count = count + 1
value = count[0]
value = value + 1
count[0] = value

这里,count没有被重新分配给任何新值,您可以通过将新创建的值分配给它来修改在内部函数外部创建的原始计数。

Python闭包的工作方式与此完全相同

所有自由变量(即既不是局部变量也不是参数的变量)都保存在内部_闭包_;属性中

In [1394]: def make_counter():
      ...:     count = 0
      ...:     def counter():
      ...:         nonlocal count
      ...:         count += 1
      ...:         return count
      ...:     return counter
      ...: 
In [1395]: f = make_counter()

In [1396]: f
Out[1396]: <function __main__.make_counter.<locals>.counter>

In [1397]: f.__closure__
Out[1397]: (<cell at 0x10af4bd98: int object at 0x10024ac20>,)

In [1399]: f.__closure__[0].cell_contents
Out[1399]: 0
在后一种情况下,您正在修改列表中的一个条目,该条目是可变的。引用被复制到_闭包_属性中

顺便说一下,make_counter是一个全局函数,因此有一个空的_closure__属性:

In [1403]: print(make_counter.__closure__)
None
您的第二个示例稍作修改:

In [1404]: def make_counter():
      ...:     count = [0]
      ...:     print(id(count))
      ...:     def counter():
      ...:         nonlocal count
      ...:         count[0] += 1
      ...:         return count[0]
      ...:     return counter
      ...: 

In [1405]: f = make_counter()
4495587464

In [1408]: id(f.__closure__[0].cell_contents)
Out[1408]: 4495587464
id是相同的