execfile('comp1.py')
def exefi(name, locals=None, globals=None):
    exec compile(open(name).read(), name, 'exec') in locals, globals
    
exefi('comp1.py')

it can execute successfully. but

#execfile('comp1.py')
def exefi(name, locals=None, globals=None):
    exec compile(open(name).read(), name, 'exec') in locals, globals
    
exefi('comp1.py')

it come with
"File "", line 39, in <module>
ex=c.end()
File "", line 17, in end
return compile(string.join(self.code, "\n"),"<code>","exec")
NameError: global name 'string' is not defined"


why?

and the is

import sys, string
class CoGen:
    
    def begin(self, tab='\t'):
        self.code=[]
        self.tab=tab
        self.level=0
        
    def end(self):
        self.code.append('')
        return compile(string.join(self.code, "\n"),"<code>","exec")
    
    def write(self, string):
        self.code.append(self.tab*self.level+string)
    
    def indent(self):
        self.level+=1
        
    def dedent(self):
        if self.level == 0:
            raise SyntaxError, "internal error in code generator"
        self.level-= 1
        
        
        
        
c= CoGen()
c.begin()
c.write("for i in range(5):")
c.indent()
c.write("print 'int code generator!'")
c.dedent()
ex=c.end()
exec ex
print ex

Dani AI

Generated

The NameError for string means the executed file’s global namespace did not contain the name when end() ran. The wrapper is changing the namespace used for execution, so imports and global names inside comp1.py end up somewhere other than the module-level globals that methods later look up.

Two practical rules to avoid this kind of bug:

  • The exec statement in Python 2 expects the globals mapping first and the locals mapping second; supplying them in the wrong order or passing non-dict/None in unexpected ways will make names vanish from the module-level globals.
  • If you want a script to behave like a module, execute it with a fresh dict that looks like a module namespace (include __name__, __file__ and __builtins__).

A simple, safe pattern to run a file in its own namespace is:

def run_file_as_module(path, module_name="__main__"):
    ns = {"__name__": module_name, "__file__": path, "__builtins__": __builtins__}
    src = open(path, "r").read()
    code = compile(src, path, "exec")
    exec code in ns
    return ns

This keeps imports (like import string) inside ns so later lookups succeed. If you want the code to run in the current globals, use execfile() or pass globals() explicitly. For running a file as an isolated module and getting its namespace back, consider runpy.run_path() (Python 2.7+). See the Python docs on the exec statement and the runpy module for details: exec statement and runpy.

As hinted, avoid accidentally shadowing built-ins or confusing parameter order; inspecting the namespace returned by your wrapper will quickly show whether string (or any other name) is present.

Recommended Answers

All 2 Replies

First of all don't use "globals" or "locals" as your identifiers, they are built-in functions.

One possibility to fix this is to do this:

#execfile('comp1.py')
def exefi(name, globalsmap=None, localsmap=None):
    if localsmap or globalsmap:
        exec compile(open(name).read(), name, 'exec') in globalsmap, localsmap
    else:
        exec compile(open(name).read(), name, 'exec') in globals()
    
exefi('comp1.py')

Another is to eliminate importing the "string" module and using join directly: return compile("\n".join(self.code),"<code>","exec")

thanks jcao219

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.