简体   繁体   中英

error with global name when running a script from another script - python

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?

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM