为什么子函数在Python中不继承作用域?

7 投票
2 回答
6551 浏览
提问于 2025-04-16 16:20

我不明白为什么下面的代码不管用:

def foo( x ):
    n = 1
    summe = 0
    def bar():
        n -= 1
    for i in range(0,10):
        y = x+i+n
        x += i
        summe += y
        print "{0} = {1} + {2} + {3}".format(y,x,i,n)
        bar()
    print "summe =", summe
    return summe

为什么bar()不能继承foo()的作用域呢?这是我需要忘记的C语言特性吗?有没有办法让我让它正常工作?

2 个回答

2

我其实是在寻找一个稍微不同的问题的解决方案时发现了这个问题。局部变量不会被子函数继承,但你可以把这个变量传递给内部函数,然后在返回时把结果赋值给它。

这还可以和PEP 3104中的nonlocal语句结合使用。这样做看起来稍微好一些,也让记住又一个Python关键字变得不那么重要。

def foo( x ):
    n = 1
    summe = 0
    def bar(n):
        n -= 1
        return n
    for i in range(0,10):
        n = bar(n)
        y = x+i+n
        x += i
        summe += y
        print "{0} = {1} + {2} + {3}".format(y,x,i,n)
    print "summe =", summe
    return summe
15

PEP 3104 解释了这个问题并提供了解决方案。问题在于,Python把对一个名字的任何赋值都当作是一个局部变量的声明。

>>> n = 1
>>> def bar():
>>>     n = n + 1
>>> 
>>> bar()
Traceback (most recent call last):
  File "<pyshell#8>", line 1, in <module>
    bar()
  File "<pyshell#7>", line 2, in bar
    n = n + 1
UnboundLocalError: local variable 'n' referenced before assignment

如果你使用的Python版本没有nonlocal这个关键词,有几种方法可以绕过这个问题。其中一个比较笨的方法是把你的变量放在一个列表里:

>>> n=[1]
>>> def bar():
>>>     n[0] = n[0] + 1
>>> 
>>> bar()
>>> n
[2]

虽然这个方法有效,但通常来说,重新编写代码以消除对非局部赋值的需求会更好。

撰写回答