在Python中函数调用时是否进行赋值?

在Python中函数调用时是否进行赋值?,python,function,variable-assignment,Python,Function,Variable Assignment,在构建参数化装饰器时,我没有意识到在Python中不允许对嵌套函数中传递的参数进行重新分配。进一步看,我意识到对于简单函数也是如此。我已将演示简化为以下嵌套函数: def a(s): def b(): def c(): # nonlocal s # fix print(s) # while s: # s -= 1

在构建参数化装饰器时,我没有意识到在Python中不允许对嵌套函数中传递的参数进行重新分配。进一步看,我意识到对于简单函数也是如此。我已将演示简化为以下嵌套函数:

def a(s):
    def b():
        def c():
#             nonlocal s                         # fix
            print(s)
#             while s:
#                 s -= 1                         # uncommenting raises UnboundLocalError 
            print(s)
            return None
        return c()
    return b()

a(3)
# 3
# 3
我希望通过添加注释的
while
循环获得以下所需的输出:

a(3)
# 3
# 0
接下来,取消注释
while
循环的两行会产生以下错误,这表明将值重新指定给
s
会引发错误:

<ipython-input-37-7141eb599936> in c()
      3         def c():
      4 #             nonlocal s                 # fix
----> 5             print(s)
      6             while s:
      7                 s -= 1                   # uncommenting raises UnboundLocalError

UnboundLocalError: local variable 's' referenced before assignment
c()中的

3 def c():
4#非局部s#修复
---->印刷品5份
6而s:
7 s-=1#取消注释会引发UnboundLocalError
UnboundLocalError:赋值前引用了局部变量's'
最后,取消注释
nonlocal
可以解决此问题,并按照建议提供所需的输出

虽然问题已经解决,但我想了解问题的根源。我注意到回溯指向第一次使用参数化参数
s
(例如
print(s)
),而不是指向实际导致错误的行(例如
while
循环/赋值)


我怀疑在调用函数时,Python首先建立本地作用域的赋值。然后,赋值优先于或重写从外部作用域继承的变量。因此,在不向
s
赋值的情况下,使用外部
s
。相反,对于赋值,
s
在函数调用时被重新定义,初始赋值之前的任何引用都会引发错误。这是正确的,还是有人能解释一下Python实际上在做什么

如果函数包含对变量的赋值(包括扩展赋值,如
-=
),则该变量自动为局部变量,除非明确声明为
全局
(或
非局部
)。如果没有赋值,则该变量自动为全局变量,无需任何声明(因为当它没有值的来源时,它很难成为局部变量)。此分析是在生成任何代码之前执行的,因此您会遇到这样的情况,即后续代码行可能会导致前一行出错。

也许您可以使用!@Windmill看看Python是如何逐行执行文件的。我感谢您的建议。目前,pythontutor显示
s
Is在
a()
的框架中可用,但它没有明确指出在嵌套函数中如何观察
s
。这证实了我的怀疑。您知道支持这一点的引用吗?