198

When I use python -m pip install <package>, how is that different from using just pip install <package>? Similarly, why would I write python -m pip install --upgrade pip to upgrade Pip, instead of just pip install --upgrade pip?

Karl Knechtel
  • 62,466
  • 11
  • 102
  • 153
Koustav Chanda
  • 2,285
  • 2
  • 8
  • 10
  • 9
    It's how you can run a [module as a script](https://www.python.org/dev/peps/pep-0338/). – jedwards Jun 12 '18 at 15:56
  • 1
    https://stackoverflow.com/questions/22241420/execution-of-python-code-with-m-option-or-not – phd Jun 12 '18 at 20:24
  • 3
    disagree with closing. closing defeats the purpose and it is a good question. Unfortunately the answers are not that good – KansaiRobot Feb 23 '20 at 04:08
  • I'm not sure what the difference in this case btw a module and a script but I find the comment: `It's how you can run a module as a script.` https://www.python.org/dev/peps/pep-0338/ to be interesting. Though the main question still remains what is a script and a module and why the `-m` is really needed. – Charlie Parker Feb 03 '22 at 19:33
  • The question **isn't actually about** what the `-m` switch for Python means; it's about the difference between using `python -m` to run the `pip` module, vs. running Pip's standalone wrapper executable. – Karl Knechtel May 03 '23 at 16:32
  • @KansaiRobot "The answers are not that good" is a point in favour of closing an older question, not against it. Especially for something that wasn't recently asked, the point of questions here **is not** to solve OP's problem, but to contribute *usefully* to a *searchable* Q&A library. – Karl Knechtel May 03 '23 at 16:34
  • I edited the question to highlight the Pip-specific point and make it *not* about the `-m` switch, since `-m` isn't the only difference between the commands. (If people disagree with the change, then it really is a duplicate after all, right?) However, this invalidates a lot of answers. We should probably have a separate canonical instead, and retire this one. Importantly, the question is commonly asked from the opposite direction: "how can I make Pip install for the correct Python?". – Karl Knechtel May 03 '23 at 16:46
  • 1
    I found a clearer duplicate for the Pip-specific part, so I added an answer there and have now duped this to both questions that can be interpreted. – Karl Knechtel May 04 '23 at 00:03

8 Answers8

123

Consider the following scenario.

You have three versions of Python installed:

  • Python 3.7
  • Python 3.8
  • Python 3.9

Your "default" version is 3.8. It's the first one appearing in your path. Therefore, when you type python3 (Linux or Mac) or python (Windows) in a shell you will start a 3.8 interpreter because that's the first Python executable that is found when traversing your path.

Suppose you are then starting a new project where you want to use Python 3.9. You create a virtual environment called .venv and activate it.

python3.9 -m venv .venv         # "py -3.9" on Windows
source .venv/bin/activate    # ".venv\Scripts\activate" on Windows 

We now have the virtual environment activated using Python 3.9. Typing python in a shell starts the 3.9 interpreter.

BUT, if you type

pip install <some-package>

Then what version of pip is used? Is it the pip for the default version, i.e. Python 3.8, or the Python version within the virtual environment?

An easy way to get around that ambiguity is simply to use

python -m pip install <some-package>

The -m flag makes sure that you are using the pip that's tied to the active Python executable.

It's good practice to always use -m, even if you have just one global version of Python installed from which you create virtual environments.

Re. path

The so-called path is a list of directories where your system searches for executables. When you type a command, like python, this list is traversed from the first directory to the last, searching for a filename that matches the command you typed.

If the filename/command is found, the matched file gets executed without taking into account potential later matches. If no match occurs, you get a Command not found or a variation thereof. This behavior is by design.

On UNIX systems the path environment variable is called $PATH, while on Windows systems it's referred to as %PATH%

More general comments about the -m-flag (Dec. 2022)

Most people viewing this will likely want the explanation given above with pip. In a more general sense though, when using python -m some_module, the -m flag makes Python execute some_module as a script. This is stated in the docs, but might be difficult to understand without some baseline knowledge.
What does it mean to "run as a script"?

In Python, a module some_module is typically imported into another Python file with an import some_module statement at the top of the importing file. This enables the use of functions, classes, and variables defined in some_module inside the importing file. To execute some_module as a script instead of importing it, you would define an if __name__ == "__main__" block inside the file. This block gets executed when running python some_module.py on the command line. This is useful because you do not want this code block to run when importing into other files, but you do want it to run when invoked from the command line.

For modules inside your project, this script/module construct should run as is, because Python will find the module from your working directory when running from the terminal:

python some_module.py

But for modules that are part of Python's Standard Library, this will not work. The example from the Python docs uses timeit (pip works the same):

python3 timeit -s 'print("hello")'  # 'python timeit.py ...' fails as well 

This returns the error: "python: can't open file '/home/<username>/timeit': [Errno 2] No such file or directory"

Adding the -m flag tells Python to look in path for timeit.py and execute the if __name__ == "__main__" clause from the file.

python3 -m timeit -s 'print("hello")'

This works as expected.

The source for the if __name__ == "__main__" block for the timeit module can be found here.

Tim Skov Jacobsen
  • 3,583
  • 4
  • 26
  • 23
  • From the doc of [venv](https://docs.python.org/3/library/venv.html): "When used from within a virtual environment, common installation tools such as pip will install Python packages into a virtual environment without needing to be told to do so explicitly." – updogliu Jan 29 '23 at 10:56
46

From Python Docs:

Since the argument is a module name, you must not give a file extension (.py). The module-name should be a valid Python module name, but the implementation may not always enforce this (e.g. it may allow you to use a name that includes a hyphen).

Package names are also permitted. When a package name is supplied instead of a normal module, the interpreter will execute <pkg>.__main__ as the main module. This behaviour is deliberately similar to the handling of directories and zipfiles that are passed to the interpreter as the script argument.

JW.
  • 2,081
  • 1
  • 20
  • 24
tourist
  • 4,165
  • 6
  • 25
  • 47
  • 5
    so this just runs the python script as a normal executable? I don't understand when I'd use the `-m` flag. My scripts always work when I run them without it. – Charlie Parker Apr 23 '21 at 17:21
  • 3
    I'm not sure what the difference in this case btw a module and a script but I find the comment: `It's how you can run a module as a script.` https://www.python.org/dev/peps/pep-0338/ to be interesting. Though the main question still remains what is a script and a module and why the `-m` is really needed. – Charlie Parker Feb 03 '22 at 19:33
22

If you type python --help

You get

// More flags above
-m mod : run library module as a script (terminates option list)
// and more flags below

A great many things in a terminal will show you how to use it if you either use command --help or man command

ggdx
  • 3,024
  • 4
  • 32
  • 48
  • 110
    The main question remains unanswered, what does it mean "to run as a script". – Serge Mosin Aug 25 '20 at 18:35
  • 1
    @SergeMosin two and half years later and still nobody has bothered to tell us.... python imports are a nightmare and the docs description is completely useless ("run as a module"??). I suspect that none of these people actually know what the flag does. Maybe nobody remembers anymore. – markemus Aug 16 '22 at 07:19
  • 1
    @markemus By calling `python -m pip [flags]`, you don't have to give the directory path to where `pip.py` exists or have that as your current working directory. Instead, python itself loads pip as a module by importing it via PYTHONPATH and then runs it, which also means that the pip.py, or any other script being run 'as a module' will not have `__name__ == '__main__'` when it is loaded and executed. – nigh_anxiety Dec 09 '22 at 20:23
20

The -m stands for module-name.

From Command line and environment:

python [-bBdEhiIOqsSuvVWx?] [-c command | -m module-name | script | - ] [args]

Bill the Lizard
  • 398,270
  • 210
  • 566
  • 880
19

When -m is used with a python statement on the command line, followed by a <module_name>, then it enables the module to be executed as an executable file.

You can refer to python docs for the same, or run python --help

SherylHohman
  • 16,580
  • 17
  • 88
  • 94
ANURAG BISHT
  • 373
  • 3
  • 7
  • 14
    so this just runs the python script as a normal executable? I don't understand when I'd use the `-m` flag. My scripts always work when I run them without it. – Charlie Parker Apr 23 '21 at 17:22
  • 6
    @CharlieParker From what I understand, the `-m` flag is useful because it will search for a module/package on all paths avaible in `sys.path` instead of just the current working directory. – qwerty_url Feb 01 '22 at 22:29
  • @qwerty_url but isn't that what usually happens? – Charlie Parker Feb 03 '22 at 19:29
  • 2
    @CharlieParker not really, if you try `python timeit` in your terminal and there isn't a file/folder named `timeit` in your current working directory you'll get a `No such file or directory` error, but if you add the `-m` flag then python will run the timeit package that comes with the standard library – qwerty_url Feb 18 '22 at 13:42
8

This is actually an interesting question, so let's explore pep 338 linked by @jedwards in the top comment.

The -m flag originally served a simpler purpose- to convert a module name into a script name. In python 2.4, the behavior was:

the command line is effectively reinterpreted from python <options> -m
<module> <args> to python <options> <filename> <args>.

This doesn't seem very useful, but that's what it did back then. Pep 338 extends this behavior further.

The semantics proposed are fairly simple [sic]: if -m is used to execute a module the PEP 302 import mechanisms are used to locate the module and retrieve its compiled code, before executing the module in accordance with the semantics for a top-level module.

It goes on to explain further that python will identify the package the module is from, import that package using the standard process, and run the module. From what I understand calling "python3 -m package.module" is the same as calling:

python3
from package import module

The -m flag will run the module as __file__ and not __main__. It will also insert the local directory into sys.path instead of the script's directory. It therefore breaks relative imports, although this was not intentional, and the authors therefore recommend to always use absolute imports. It also depends on how you call it- "python3 -m package.module" is not the same as "python3 -m module".

In theory it's simple- it loads up python and imports the module instead of dumping the code into __main__. In practice that has many effects. It's a different import system that behaves differently. Some of those changes were not intentional and were only discovered after implementation. Python's imports are a mess and it's okay to be confused.

markemus
  • 1,702
  • 15
  • 23
  • Do you have any idea why -m requires dot notation? I use it to reproduce the effect of the ipython command "run package/module.py" with the python command for better memory management. The dot notation is a major drawback to this workflow. – nedlrichards Oct 23 '22 at 14:59
  • 1
    @nedlrichards it matches the import syntax inside of a script, and I believe it will allow you to properly load submodules that depend on __init__ for construction. – markemus Oct 25 '22 at 08:33
5

Amazing this is so hard to answer when some people say the question is too simple to bother with.

As far as I can tell, the practical purpose is so you can use dot notation to run your script when you aren't in the directory.

You can run python -m path.to.my.happy.place

instead of being in path/to/my/happy and running python place.py

Jonathan Mugan
  • 632
  • 2
  • 9
  • 12
  • why would you want to use dot notation? It is a mess and doesn't autocomplete on a command line. – nedlrichards Oct 23 '22 at 14:57
  • 1
    @nedlrichards One example is what I ran into where a .py file I was running was in a folder, and the custom library I made was up one level, and then in a different folder. I kept running into errors such as "Attempted relative import with no known parent package". To fix that, I had to use the -m flag, and run my .py file with dot.notation in the terminal. The same way was used to run on AWS Lambda and it worked. – Kush Apr 10 '23 at 14:12
2

If you have multiple versions of python installed and you want to upgrade pip pip install --upgrade pip how do you know which python version will be affected? it depends on path variable for the shell. You might also get warning in this case. To avoid this confusion use -m then it looks in variable sys.path. This is another advantage of -m.

# importing module
import sys
  
# printing all directories for 
# interpreter to search
sys.path
Blue Clouds
  • 7,295
  • 4
  • 71
  • 112