3

Let's say I have two scripts:

test_fun1.py

a = 1

def test1():
    print a
    execfile('test_fun2.py')

test1()

test_fun2.py

b = 2    

def print_a():
    print 'a'

def test2():
    print_a()
    print b

test2()

When I run test_fun1.py I get this error:

NameError: global name 'print_a' is not defined

If I exclude the print_a() within test2() both a and b are printed. Why would variables be set to global but functions wouldn't?

6
  • You mean both a and b are printed from test_fun2.py? (or could it be from test1())? Also, have you considered just importing external scripts? Commented Aug 13, 2013 at 18:51
  • 1
    Maybe this can help you? stackoverflow.com/questions/2904274/… Commented Aug 13, 2013 at 18:53
  • @sihrc: a is printed from test1() and b is printed from test2() when print_a() is excluded from the code. Commented Aug 13, 2013 at 18:55
  • So, variables aren't "global" then. Commented Aug 13, 2013 at 18:59
  • @sihrc: what I meant was that I can use a and b inside the functions although they've been defined outside it. I haven't declared them global with the "global" command though. Commented Aug 13, 2013 at 19:06

1 Answer 1

1

This is a pretty interesting problem. First a quick workaround, you can provide dictionaries to use as the local and global namespace when calling execfile(), using an empty dictionary for globals works fine:

# test_fun1.py
a = 1

def test1():
    print a
    execfile('test_fun2.py', {})

test1()

Alternatively, if you want the code to execute within the global scope of your module you can use globals() instead of {}.

Now on to why this isn't working... from the documentation on execfile():

If both dictionaries are omitted, the expression is executed in the environment where execfile() is called.

Here "both dictionaries" is referring to the optional globals and locals arguments to execfile(). In this case "the environment where execfile() is called" is the local scope of the function test1() in test_fun1.py. Now it is reasonable to still expect this to work, because it seems like it should be doing something essentially equivalent to the following:

a = 1

def test1():
    print a
    # code executed by execfile
    b = 2    

    def print_a():
        print 'a'

    def test2():
        print_a()
        print b

    test2()

test1()

However there is a note later on in the docs:

Note: The default locals act as described for function locals() below: modifications to the default locals dictionary should not be attempted. Pass an explicit locals dictionary if you need to see effects of the code on locals after function execfile() returns. execfile() cannot be used reliably to modify a function’s locals.

So there you have it, there is an explicit warning here that execfile() cannot be used to reliably modify a function's locals, and that is exactly what this code is attempting to do. The b = 2 and def print_a(): ... statements are executed within the scope of test1(), but they are not actually succeeding in adding those names to the namespace so attempting to access those names later on fails.

Sign up to request clarification or add additional context in comments.

2 Comments

Thanks for your answer. I'm actually able to use b inside test2() - when the print_a() statement is removed from test2() both a and b are printed, so I can still access b. Does your explanation just apply to functions then?
Unfortunately the documentation is kind of vague when it says "execfile() cannot be used reliably to modify a function's locals". It very well could be that there is a difference here between variable assignment and function definitions, but I don't really know and I am not about to dig through the Python source code to find out. The point here is that you should really be providing a globals argument to execfile() or the behavior will be inconsistent depending on where the call occurs.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.