Search code examples
pythonscopeexec

Python exec and __name__


When I run:

exec("print(__name__)")

it prints __main__.

But when I run:

exec("print __name__", {})

it prints builtins.

How to make the second example to also print __main__?

What I try to achieve is to run a piece of code with exec() so that from the perspective of the it looks like it was run from command line.

I would like to tun the code with clean scope but the second example breaks the code relying on if __name__ == "__main__". How to fix this?


Solution

  • You could use imp.load_module instead:

    import imp
    
    with open(mainfile) as src:
        imp.load_module('__main__', src, mainfile, (".py", "r", imp.PY_SOURCE))
    

    This imports the file as the __main__ module, executing it.

    Note that it takes an actual file object when the type is set to imp.PY_SOURCE, so you'd need to create a temporary file for this to work if your source code comes from somewhere other than a file.

    Otherwise, can always set __name__ manually:

    >>> src = '''\
    ... if __name__ == '__main__': print('Main!')
    ... else: print('Damn', __name__)
    ... '''
    >>> exec(src)
    Main!
    >>> exec(src, {})
    Damn builtins
    >>> exec(src, {'__name__':'__main__'})
    Main!