1

I have a function which will recursively execute another function inside and I want to share variable for all execution of that function.

Something like that:

def testglobal():
  x = 0
  def incx():
    global x
    x += 2
  incx()
  return x
testglobal() # should return 2

However, I'm getting error NameError: name 'x' is not defined

There is hacky solution to make list and use first value of that list as x. But this is so ugly.

So how can I share x with incx function ? Or should I use completely different approach ?

1
  • 1
    In python 3 there is a new keyword, nonlocal, that does exactly what you want. Keep in mind that this is a closure so you have access to x without alterations, but assigning (e.g. x = 1) inside incx will make x local to incx and therefore not refer to the same variable. nonlocal achieves this. Commented Sep 23, 2016 at 14:28

3 Answers 3

3

This will work unless you are still using Python 2.x:

def testglobal():
  x = 0
  def incx():
    nonlocal x
    x += 2
  incx()
  return x

testglobal() # should return 2

Possible a cleaner solution though would be to define a class to store your state between method calls.

Sign up to request clarification or add additional context in comments.

Comments

2

Use the nonlocal statement, so incx will use the x variable from testglobal:

def testglobal():
    x = 0
    def incx():
        nonlocal x
        x += 2
    incx()
    return x

testglobal()

Comments

1

You want to use the nonlocal statement to access x, which is not global but local to testglobal.

def testglobal():
  x = 0
  def incx():
    nonlocal x
    x += 2
  incx()
  return x
assert 2 == testglobal() 

The closest you can come to doing this in Python 2 is to replace x with a mutable value, similar to the argument hack you mentioned in your question.

def testglobal():
  x = [0]
  def incx():
    x[0] += 2
  incx()
  return x[0]
assert 2 == testglobal()

Here's an example using a function attribute instead of a list, an alternative that you might find more attractive.

def testglobal():
  def incx():
    incx.x += 2
  incx.x = 0
  incx()
  return inc.x
assert 2 == testglobal() 

2 Comments

But this was introduced only in python 3, right ? But this concept looks so common for, how to do the same in python 2 ?
You can't, short of your mutable-argument hack. Closures only capture the value of a variable for reading; you can't modify the value nonlocally (which is why Python 3 added the nonlocal keyword).

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.