3

I'm having an issue with running a python script in a python script that i simply do not understand:

Assume we have 2 files in the same directory: 'init.py' and 'text.py'

init.py:

X = 5
print("init.py was run")

test.py:

exec(open("./init.py").read())
print("X = %s" %X)

If I run test.py now, I get

init.py was run

X = 5

However, if I change test.py into:

def func_call( filename):
  exec(open(filename).read())
  print("X = %s" %X)

func_call("./init.py")

I get:

init.py was run

Traceback (most recent call last):

File "test.py", line 5, in

func_call("./init.py")   

File "test.py", line 3, in func_call

print("X = %s" %X) 

NameError: name 'X' is not defined

Can someone explain to me why this leads to different results? Is there a workaround for this? My goal is to initializes most of my variables by running a python script and accessing the variables set up in that python script.

Alessandro
  • 742
  • 1
  • 10
  • 34
Smudoxo
  • 85
  • 1
  • 9
  • Why don't you create file `const.py` and import it? – How about nope Sep 08 '17 at 09:04
  • That actually works and solves the issue, thank you! However I still don't understand why this is happening.... – Smudoxo Sep 11 '17 at 06:02
  • 1
    see also [NameError using execfile in python](https://stackoverflow.com/a/20475760/3066295) and [What is an alternative to execfile in Python 3?](https://stackoverflow.com/questions/436198/what-is-an-alternative-to-execfile-in-python-3) – TT-- Feb 06 '18 at 23:36

1 Answers1

5

According to exec_documentation:

If exec gets two separate objects as globals and locals, the code will be executed as if it were embedded in a class definition.

Inside method globals() and locals() are different objects:

def method():
    print(globals() == locals())
    exec('X=10')
    print('Method execution =', X)

method()

output:

False
NameError: name 'X' is not defined

In global level this objects are equal:

print(globals() == locals())
exec('X=99')
print('Global exec =', X)

Output:

True
Global exec = 99

So If you want to do it via method, you need to pass the same object to exec. For your code it would look like this:

def func_call(filename):
  exec(open(filename).read(), globals(), globals())
  print("X = %s" %X)

func_call("./init.py")

Nevertheless, as I mentioned in comment, create file with consts and import it. Try to avoid using exec/eval at all costs, unless you are 100% sure what you are doing.

How about nope
  • 752
  • 4
  • 13