6

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?

2 Answers 2

6

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!
Sign up to request clarification or add additional context in comments.

8 Comments

I cannot unfortunately create a temporary file on disk. Isn't there a way to execute plain string as if it was run from command line? And one more question about your reply: it looks like it as if it was importing (as in import) the file - does it import or execute the file? Is there a difference?
In order to import a module, it has to be executed.
Note that the expectation that __name__ == '__main__' works implies you are executing modules here.
I'm sorry I don't understand your last comment - what do you mean by "here"? The src string? And I have to ask similar question as for the other answer - is in {'__name__':'__main__'} enough to make src believe it was executed from command line? I mean are there any traps I should know about? If it is enough though that would make it for a perfect solution, thanks in any case...
'here' as in your question. __name__ is a module global, in modules globals and locals are the same thing so you should not supply a locals mapping. Testing for __name__ is the defacto way to test if this is the main script, setting it is enough.
|
0

One solution is to provide the __name__ explicitly in your execution dict:

exec("print(__name__)", {'__name__': '__main__'})

1 Comment

Is it safe? I mean is the only difference between the code from question and running the code from command line only this fix? I know there are more keys like __doc__ but is this fix essential to making it look like code from command line?

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.