131

In the 2nd case below, Python tries to look for a local variable. When it doesn't find one, why can't it look in the outer scope like it does for the 1st case?

This looks for x in the local scope, then outer scope:

def f1():
    x = 5
    def f2():
         print x

This gives local variable 'x' referenced before assignment error:

def f1():
    x = 5
    def f2():
        x+=1

I am not allowed to modify the signature of function f2() so I can not pass and return values of x. However, I do need a way to modify x. Is there a way to explicitly tell Python to look for a variable name in the outer scope (something similar to the global keyword)?

Python version: 2.7

Dhara
  • 6,587
  • 2
  • 31
  • 46

2 Answers2

187

In Python 3.x this is possible:

def f1():
        x = 5
        def f2():
                nonlocal x
                x+=1
        return f2

The problem and a solution to it, for Python 2.x as well, are given in this post. Additionally, please read PEP 3104 for more information on this subject.

Community
  • 1
  • 1
hochl
  • 12,524
  • 10
  • 53
  • 87
79
def f1():
    x = { 'value': 5 }
    def f2():
        x['value'] += 1

Workaround is to use a mutable object and update members of that object. Name binding is tricky in Python, sometimes.

Tom Whittock
  • 4,081
  • 19
  • 24
  • 1
    This works, although I ended up using a list with a single element instead of a dictionary. Thanks! – Dhara Aug 17 '12 at 07:21
  • 16
    I think it is more correct to use `nonlocal` or `global` – bgusach Dec 03 '13 at 08:39
  • 5
    Global is not a good idea as it will pollute the global namespace. Nonlocal is a python 3 feature, and this question specified python 2.7. – Tom Whittock Dec 04 '13 at 11:08
  • 2
    *global* doesn't work in py2.7 for question purpose, however `x['value']` is harder to write on parent scope than just `value`, so consider passing value to nested function, and then just returning `value` from nested scope to parent scope – Sławomir Lenart Jul 18 '18 at 15:59