Generally, global scope is used with exec
a = 100
b = 200
snip = '''
c = a+b
'''
exec(snip)
print(c)
However, this can be problematic in some use cases. exec
allows you to pass in a dictionary defining the global scope, and receive a dictionary containing the local scope. Here's an example:
snip = '''
c = a+b
'''
input_globals = {'a': 100, 'b': 2}
output_locals = {}
exec(snip, input_globals, output_locals)
print(output_locals)
This results in the following output:
{'c': 102}
this effectively allows one to use exec "functionally", without working on and modifying global scope.
You can read this for more detail.