5

As I understand the global statement in the code below, it should prevent function_two from rebinding the name test and instead modify test in function_one. However, I get NameError: global name 'test' is not defined.

def function_one():
    test = 1
    def function_two():
        global test
        test += 1
    function_two()
    print test
function_one()

I have looked and I can't find an example like this. What am I missing?

10
  • 3
    You misunderstood. global does not mean the same thing as nonlocal (Python 3 only). global really means global, e.g. not in a function. test in function_two expects there to be a global name test; the local name test in function_one() is ignored. Commented Dec 29, 2015 at 20:09
  • 1
    Are you using Python 2 or Python 3? Presumably Python 2, since you use print as a statement. Commented Dec 29, 2015 at 20:09
  • 2
    @name_no: no, that'll not work. You'll get a UnboundLocalError: local variable 'test' referenced before assignment exception. Commented Dec 29, 2015 at 20:10
  • 1
    Related: python.org/dev/peps/pep-3104 Commented Dec 29, 2015 at 20:11
  • 1
    Yes, it is code without a purpose. I just wanted a simple example that demonstrated my confusion with the global statement. The answers were very enlightening. Commented Dec 30, 2015 at 15:47

1 Answer 1

9

Python 2 does not support the concept of a non-local. Closures (accessing test from a parent function) only support read access, not assignment in Python 2.

The global keyword really does mean global, e.g. that the name lives in the module (global) namespace. The namespace of the function_one() function is not global, it is local (to that function).

In Python 3, you can mark a name as nonlocal, which would make your example work as expected. See PEP 3104 - Access to Names in Outer Scopes.

In Python 2, you'll have to resort to tricks instead. Make the name an attribute of the nested function, for example. 'reading' the function object as a closure is allowed, as is setting attributes on such closed-over objects:

def function_one():
    def function_two():
        function_two.test += 1

    function_two.test = 1
    function_two()

    print test

Another trick is to use a mutable object, such as a list or a dictionary. Again, you are only reading the closed-over name, then altering the resulting object directly:

def function_one():
    test = [1]

    def function_two():
        test[0] += 1

    function_two()

    print test[0]
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.