0

I have read Cannot change global variables in a function through an exec() statement?, but this is not my case.

When i run test(), it raises exception UnboundLocalError: local variable 'var' referenced before assignment, it looks like exec('global var', globals()) doesn't work.

var = 1

def test():
    exec('global var', globals()) # The effect it achieves is different from `global var`, why? 
    var += 1  

test()
print(var)

But if i change the function to the following, it worked:

def test():
    exec('global var', globals())
    exec('var += 1', globals())

I don't know why, can anyone explain?

fitz
  • 540
  • 4
  • 11
  • @TomKarzes You are right, the first `exec` isn't needed , but the globals() argument to the second `exec` is needed. If i change the function to `def test():exec('var += 1')`, the change of 'var' will not be affected outside the function, thanks! – fitz Aug 03 '21 at 08:08
  • Oops, you're right. I fooled myself because it doesn't give an error if the `globals()` argument is removed, but it also doesn't update the global version of `var` without it. I'm not sure what it updates. – Tom Karzes Aug 03 '21 at 09:42

2 Answers2

3

The following quote from the language reference (section "Simple statements") seems relevant:

Programmer’s note: global is a directive to the parser. It applies only to code parsed at the same time as the global statement. In particular, a global statement contained in a string or code object supplied to the built-in exec() function does not affect the code block containing the function call, and code contained in such a string is unaffected by global statements in the code containing the function call. The same applies to the eval() and compile() functions.

I.e, in your first version, var is still local to the function.

Ture Pålsson
  • 6,088
  • 2
  • 12
  • 15
1

'global var' only has meaning within the context of the dynamically created program (DCP).

Consider these two options for incrementing var. They may make it more obvious what's going on.

exec('var += 1', globals())

...or...

exec('global var\nvar += 1')

In the first case the Python runtime finds var because you passed the dictionary of globals to exec(). In the second case, you qualified var with 'global' so the runtime knows where to look. Note therefore that in the second case there's no need to pass globals()