The python interpreter has -m
module option that "Runs library module module as a script".
With this python code a.py:
if __name__ == "__main__":
print __package__
print __name__
I tested python -m a
to get
"" <-- Empty String
__main__
whereas python a.py
returns
None <-- None
__main__
To me, those two invocation seems to be the same except __package__ is not None when invoked with -m option.
Interestingly, with python -m runpy a
, I get the same as python -m a
with python module compiled to get a.pyc.
What's the (practical) difference between these invocations? Any pros and cons between them?
Also, David Beazley's Python Essential Reference explains it as "The -m option runs a library module as a script which executes inside the __main__ module prior to the execution of the main script". What does it mean?
The main reason to run a module (or package) as a script with -m is to simplify deployment, especially on Windows. You can install scripts in the same place in the Python library where modules normally go - instead of polluting PATH or global executable directories such as ~/.local (the per-user scripts directory is ridiculously hard to find in Windows).
Then you just type -m and Python finds the script automagically. For example,
python -m pip
will find the correct pip for the same instance of Python interpreter which executes it. Without -m, if user has several Python versions installed, which one would be the "global" pip?If user prefers "classic" entry points for command-line scripts, these can be easily added as small scripts somewhere in PATH, or pip can create these at install time with entry_points parameter in setup.py.
So just check for
__name__ == '__main__'
and ignore other non-reliable implementation details.When you use the
-m
command-line flag, Python will import a module or package for you, then run it as a script. When you don't use the-m
flag, the file you named is run as just a script.The distinction is important when you try to run a package. There is a big difference between:
and
as in the latter case,
foo.bar
is imported and relative imports will work correctly withfoo.bar
as the starting point.Demo:
As a result, Python has to actually care about packages when using the
-m
switch. A normal script can never be a package, so__package__
is set toNone
.But run a package or module inside a package with
-m
and now there is at least the possibility of a package, so the__package__
variable is set to a string value; in the above demonstration it is set tofoo.bar
, for plain modules not inside a package, it is set to an empty string.As for the
__main__
module; Python imports scripts being run as it would a regular module. A new module object is created to hold the global namespace, stored insys.modules['__main__']
. This is what the__name__
variable refers to, it is a key in that structure.For packages, you can create a
__main__.py
module and have that run when runningpython -m package_name
; in fact that's the only way you can run a package as a script:So, when naming a package for running with
-m
, Python looks for a__main__
module contained in that package and executes that as a script. It's name is then still set to__main__
, and the module object is still stored insys.modules['__main__']
.Execution of Python code with -m option or not
Use the
-m
flag.The results are pretty much the same when you have a script, but when you develop a package, without the
-m
flag, there's no way to get the imports to work correctly if you want to run a subpackage or module in the package as the main entry point to your program (and believe me, I've tried.)The docs
Like the docs say:
and
so
is roughly equivalent to
(assuming you don't have a package or script in your current directory called pdb.py)
Explanation:
Behavior is made "deliberately similar to" scripts.
Some python code is intended to be run as a module: (I think this example is better than the commandline option doc example)
And from the release note highlights for Python 2.4:
Follow-up Question
It means any module you can lookup with an import statement can be run as the entry point of the program - if it has a code block, usually near the end, with
if __name__ == '__main__':
.-m
without adding the current directory to the path:A comment here elsewhere says:
Well, this demonstrates the possible issue - (in windows remove the quotes):
Use the
-I
flag to lock this down for production environments (new in version 3.4):from the docs:
What does
__package__
do?It enables explicit relative imports, not particularly germane to this question, though - see this answer here: What's the purpose of the "__package__" attribute in Python?