开发者

UnboundLocalError with operators and functional programming in python (methods work fine) [duplicate]

This question already has answers here: Is it possible to modify a variable in python that is in an outer (enclosing), but not global, scope? (9 answers) Python difference between mutating and re-assigning a list ( _list = and _list[:] = ) (3 answers) Closed 21 days ago.

prog1.py:

def runf(f):
    f()

def main():
    l = [0]
    def f():
        l.append(1)
    runf(f)
    print(l)

main()

Gives me (as expected):

[0, 1]

prog2.py:

def runf(f):
    f()

def main():
    l = [0]
    def f():
        l += [1] # <-- Only difference
    runf(f)
    print(l)

main()

Gives me:

Traceback (most recent call last):
  File "prog2.py", line 11, in <mod开发者_Go百科ule>
    main()
  File "prog2.py", line 8, in main
    runf(f)
  File "prog2.py", line 2, in runf
    f()
  File "prog2.py", line 7, in f
    l += [1]
UnboundLocalError: local variable 'l' referenced before assignment

Could someone please explain to me what's going on here?

Note: This happens in both python2 and python3.

Also, I'm open to suggestions on a better title for this question.


The execution model reference of Python (section 4.1) states:

If a name is bound in a block, it is a local variable of that block.

What happens is that l += [1], for the sake of binding is equivalent to l = l + [1] which means l is bound inside f. Here's another interesting document reference:

Assignment of an object to a single target is recursively defined as follows.

If the target is an identifier (name):

  • If the name does not occur in a global statement in the current code block: the name is bound to the object in the current local namespace.
  • Otherwise: the name is bound to the object in the current global namespace.

The otherwise clause is relevant here. Since you did not declare global l in the scope of f and assigned to l, the name is bound in the local namespace of f. Then, the reference to it implicitly created by l += [1] refers to a variable that hasn't been defined yet. Hence the UnboundLocalError.


P.S. global l wouldn't help you, by the way. Python 3 has the nonlocal statement to handle cases like this:

The nonlocal statement causes the listed identifiers to refer to previously bound variables in the nearest enclosing scope. This is important because the default behavior for binding is to search the local namespace first. The statement allows encapsulated code to rebind variables outside of the local scope besides the global (module) scope.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜