1

When I have exec() in defined function it is not working ('NameError: name 'a' is not defined'):

def abc():
    qwerty = "a = 2"
    exec(qwerty)
abc()
print(a)

but, when I won't use def, it is working:

qwerty = "a = 2"
exec(qwerty)
print(a)

How can I "repair" it, or are there other similar solutions? (I can't execute this at start, I need to call that function in the middle of the program)

LOR3MI
  • 27
  • 5
  • 2
    When you execute `a = 2` inside the function, it gets defined in the local scope, then once you get to `print(a)` you are outside that scope. You could probably declare the variable global at the start of `abc`. – RecencyEffect Apr 04 '21 at 11:32
  • 2
    Does this answer your question? [Running exec inside function](https://stackoverflow.com/questions/2626582/running-exec-inside-function) – Yash Apr 04 '21 at 11:33
  • Check LEGB variable scope. – Lawhatre Apr 04 '21 at 11:37
  • exec() to dynamically execute Python code- this can be a string or some object code. When it is object code, Python executes it. But exec() doesn’t return a value; it returns None. Hence, we cannot use return and yield statements outside function definitions. – sudhee_bsp Apr 04 '21 at 11:41
  • 1
    Also, obligatory warning: `exec` should almost never be used unless you are absolutely sure it's the only and correct solution. Many new programmers learn about `exec` or `eval` and think they are solutions to their problems, when 99.99% of the time there are much better ways to solve your problem. Code with `exec` and `eval` usually becomes very hard to read or understand for a professional programmer, and they potentially creates many security issues in your program. They're also slower than the alternatives. I've yet to ever needed to use, or seen, them in a production program. – Ted Klein Bergman Apr 04 '21 at 11:50

3 Answers3

2

My answer is similar to @Cyrill's answer but with some subtle differences.
There are 3 ways to call the exec function:

  1. With 1 argument, e.g. exec('a = 2'). This will execute the statement in the current scope and thus create a local variable.
  2. with 2 arguments, e.g. exec('a = 2', globals()). This will execute the statement in the suplied global namespace, which is also the current global namespace (returned by globals()). This will mutate the global namespace.
  3. with 3 arguments, e.g. exec('a = 2', globals(), loc). This will execute the statement in the suplied local namespace (the third argument) using the suplied global namespace as the global namespace. This will mutate the local namespace.

By using the second way we can execute code in the global namespace, so:

def abc():
    qwerty = 'a = 2'
    exec(qwerty, globals())
abc()
print(a)  # outputs 2
Roy Cohen
  • 1,540
  • 1
  • 5
  • 22
1

You are missing a parameter on exec() function

variables used inside the exec function cannot be accessed as if they where declared globally

a workaround would be to pass 2 dictionaries in exec()
as such, i normally would do that like this..

loc = {}
def abc():
    qwerty = "a = 2"
    exec(qwerty, globals(), loc)
abc()
print(loc['a'])

which would then output 2

Riven
  • 375
  • 2
  • 11
0

In my case, the Riven's comment helped me a lot:

loc = {}
def abc():
    qwerty = "a = 2"
    exec(qwerty, globals(), loc)
abc()
print(loc['a'])

In my case I had main script which called a second script. I needed to use the "c" variable within the second script. Therefore I used locals(),loc as arguments for exec().

loc = {}
a = 10
b = 5
def abc(a,b):
    qwerty = "c = %d + %d"%(a,b)
    exec(qwerty, locals(), loc)
    c = loc['c']
    d = c+2
    print(d)

abc(a,b)