0

I encounter this confusing behaviour when working with the exec() function in Python.

Code1:

def add(a, b):
    exec("c = a+b")
    print(locals())
    return 1

add(3,4)

this prints

{'a': 3, 'b': 4, 'c': 7}

and returns 1 as expected. However, if I try to have another variable with name c, it doesn't work.

Code2:

def add(a, b):
    exec("c = a+b")
    print(locals())
    c = 2
    print(locals())
    return 1

add(3,4)

Code2 prints

{'a': 3, 'b': 4}
{'a': 3, 'b': 4, 'c': 2}

and returns 1. Can anybody explain this to me, please?

Ahmed Elashry
  • 389
  • 2
  • 12
  • why do you use `exec()`? – furas Jul 22 '22 at 09:29
  • It's irrelevant here. These snippets are just to illustrate the issue, but I am using `exec()` to get around creating multiple scripts for slightly different situations. – Ahmed Elashry Jul 22 '22 at 09:38
  • it can be relevant - maybe there is better method. Maybe using `exec()` can make more problems. – furas Jul 22 '22 at 09:49
  • Yes, of course you are right, but it is another question and I am curious now what is happening under the hood of the codes I provided – Ahmed Elashry Jul 22 '22 at 09:52

1 Answers1

1

It is to do with memory allocation and how exec runs.

First of all, variables in a function are stored in a stack, the memory for all variables in the function is allocated when the bytecode is compiled (note this does not mean that they are given a value at that time). If you define the variable "c" in your function somewhere, it will be allocated a space in memory. If you want to learn more about this from someone who explained it a lot better than I did, I suggest you check out this post: How is memory allocated for variables in Python?

Secondly, exec() is run dynamically and cannot edit any local variables (check out the documentation: https://docs.python.org/3/library/functions.html#exec). Dynamically means that the statement in the brackets is not compiled to bytecode with the rest of the function but when the exec bytecode is run. The exec function can create local variables but not edit them directly, this includes variables yet to be declared in the scope, as they will have memory allocated to them (even if there is no value stored there yet).

Finally, in Code1, the variable "c" is not defined outside the exec(), so when the exec is run "c" is then allocated the memory and is assigned the value. However, in Code2, "c" is defined in the function (even if it is after the exec()), so the memory is allocated when the function is compiled to bytecode, meaning that when the exec function runs, it won't be able to change the value of "c" as it already exists in memory.

OFitz
  • 26
  • 1