{"course":{"slug":"python-for-ai","title":"Python, from Zero, for AI","url":"https://addaly.com/learn/python-for-ai","level":"beginner","track":"build"},"lesson":{"slug":"packages-and-venvs","title":"Installing packages, and why virtual environments exist","url":"https://addaly.com/learn/python-for-ai/packages-and-venvs","position":46,"of":89,"minutes":7,"answer":"A virtual environment is a per-project folder of packages, and activation lasts only for one terminal session.","keyIdea":"A virtual environment is a per-project folder of packages, and activation lasts only for one terminal session."},"body":{"format":"markdown","text":"## Other people's code\n\nPython comes with a large standard library: `json`, `os`, `random`, `datetime` and a few hundred more. Those need no installing:\n\n```python\nimport random\nprint(random.choice([\"heads\", \"tails\"]))\n```\n\nEverything else lives on PyPI, a public archive of packages anyone can publish to, and you fetch it with `pip`. `requests` for HTTP. `pandas` for tables. `openai` or `anthropic` for AI APIs.\n\n## Why not just install everything system-wide\n\nTwo reasons, and they are not theoretical.\n\nFirst, your operating system uses Python for its own work. On many Linux systems, parts of the package manager and desktop are written in it. Installing or upgrading packages into that Python can break things that have nothing to do with your project.\n\nSecond, and more common: two of your projects will eventually need different versions of the same package. Project A was written against version 1 and breaks on version 2. Project B needs version 2. There is one system Python and one slot per package, so one of them loses.\n\nA **virtual environment** is the fix. It is an ordinary folder containing its own `python` and its own place to put packages. Install into it and nothing outside is touched. Delete the folder and the install is undone completely. Every project gets its own.\n\n## Making one\n\n```bash\ncd my-project\npython3 -m venv .venv\n```\n\nThat creates a folder called `.venv`. Now activate it, which means \"for this terminal session, `python` and `pip` mean the ones inside `.venv`\":\n\n```bash\nsource .venv/bin/activate      # macOS or Linux\n.venv\\Scripts\\activate         # Windows PowerShell\n```\n\nYour prompt changes to show `(.venv)`. Now install:\n\n```bash\npython -m pip install requests\n```\n\nWhen you are finished, `deactivate` puts the terminal back to normal. Add `.venv/` to `.gitignore`; it is rebuildable and large, and it never belongs in a repository.\n\nUse `python -m pip install` rather than bare `pip install`. It guarantees the pip you run belongs to the python you are running, which removes the most common cause of the next section.\n\n## The error that will happen to you\n\n```\nModuleNotFoundError: No module named 'requests'\n```\n\nThis almost never means the install failed. It means the Python running your script is not the Python you installed into. Diagnose it from inside the program, not by guessing:\n\n```python\nimport sys\nprint(sys.executable)\n```\n\nIf that prints a system path like `/usr/bin/python3` and you installed into `.venv`, there is your answer. Common causes: you opened a new terminal and forgot to activate, since activation only applies to one shell session; or your editor is configured to run a different interpreter than your terminal uses.\n\nA related message you may see on Debian, Ubuntu or a Raspberry Pi:\n\n```\nerror: externally-managed-environment\n```\n\nThat is not a bug. The system is refusing to let you install into the Python it depends on, and telling you to make a virtual environment. Make one.\n\n## Recording what a project needs\n\n```bash\npython -m pip freeze > requirements.txt\n```\n\nThat writes every installed package and its exact version into a file. Someone else, or you on another machine, can then reproduce your setup:\n\n```bash\npython3 -m venv .venv\nsource .venv/bin/activate\npython -m pip install -r requirements.txt\n```\n\nCommit `requirements.txt`. It is small, it is text, and it is the difference between \"works on my machine\" and \"works\".\n\n## Import, once installed\n\n```python\nimport requests\nprint(requests.__version__)\n\nfrom datetime import date\nprint(date.today())\n```\n\nInstalling and importing are separate steps. `pip install` puts the code on your disk, once. `import` loads it into a running program, and belongs at the top of every file that uses it.\n\nOne honest caution about PyPI: anyone can publish there, and names close to popular packages are sometimes registered by people hoping you will mistype. Check the spelling of a package before you install it, and prefer the name given in the official documentation over one you half-remember.\n\n## Try this now\n\nMake a folder, create a venv, activate it, install `requests`, then run a file containing `import sys, requests` and `print(sys.executable)`. Then open a brand new terminal, do not activate, and run the same file. Read the error you get, and check it against what you now know."},"check":{"question":"You created `.venv`, activated it, installed `requests`, and your script ran. The next day you open a fresh terminal, go to the same folder, run the same script, and get `ModuleNotFoundError: No module named 'requests'`. What is the most likely cause?","options":[{"text":"The install needed administrator rights and silently failed, so nothing was ever written to disk.","correct":false,"tempting":"Permission problems are a genuine cause of failed installs, and reaching for sudo is folk advice that sometimes appears to work."},{"text":"The fresh terminal is running the system Python, because activation applies only to the shell session you did it in.","correct":true},{"text":"`requests` was installed for one Python version and the script is being run by a different, older one.","correct":false,"tempting":"Having several Pythons on one machine is real and does cause exactly this message, so it is a sound diagnosis that happens to be the wrong one here."},{"text":"Only the file you tested in has the import; the package has to be imported in every file in the folder before it can be found.","correct":false,"tempting":"Installing and importing both feel like ways of making a package available, so blurring the two leads to a plausible file-level explanation."}]},"prev":{"slug":"streaming-large-files","title":"Files larger than memory","url":"https://addaly.com/learn/python-for-ai/streaming-large-files"},"next":{"slug":"dependencies-and-pinning","title":"Pinning dependencies, so it still runs next year","url":"https://addaly.com/learn/python-for-ai/dependencies-and-pinning"},"authorship":"Founder and series editor: Dr Mustafa Mun. Written by AI models to a written standard. Exam keys checked blind by a second model: 3,665 of 3,666 agreed. Academic review invited.","review":{"status":"Draft, open for academic review"},"cite":"Addaly (2026) 'Installing packages, and why virtual environments exist', in Python, from Zero, for AI. Edited by M. Mun. Addaly. Available at: https://addaly.com/learn/python-for-ai/packages-and-venvs (Accessed: 31 October 2026).","licence":{"name":"CC BY-NC-SA 4.0","url":"https://creativecommons.org/licenses/by-nc-sa/4.0/"},"reader":{"schema":1,"title":"Installing packages, and why virtual environments exist","courseTitle":"Python, from Zero, for AI","module":{"index":5,"slug":"files-formats-environments","title":"Data in and out: files, formats and the environment"},"answer":null,"keyIdea":"A virtual environment is a per-project folder of packages, and activation lasts only for one terminal session.","hero":{"kind":"plate","image":null,"alt":null,"caption":null},"blocks":[{"t":"h2","id":"other-people-s-code","runs":[{"text":"Other people’s code"}]},{"t":"p","runs":[{"text":"Python comes with a large standard library: "},{"text":"json","code":true},{"text":", "},{"text":"os","code":true},{"text":", "},{"text":"random","code":true},{"text":", "},{"text":"datetime","code":true},{"text":" and a few hundred more. Those need no installing:"}]},{"t":"code","lang":"python","label":"Python","text":"import random\nprint(random.choice([\"heads\", \"tails\"]))"},{"t":"p","runs":[{"text":"Everything else lives on PyPI, a public archive of packages anyone can publish to, and you fetch it with "},{"text":"pip","code":true},{"text":". "},{"text":"requests","code":true},{"text":" for HTTP. "},{"text":"pandas","code":true},{"text":" for tables. "},{"text":"openai","code":true},{"text":" or "},{"text":"anthropic","code":true},{"text":" for AI APIs."}]},{"t":"h2","id":"why-not-just-install-everything-system-wide","runs":[{"text":"Why not just install everything system-wide"}]},{"t":"p","runs":[{"text":"Two reasons, and they are not theoretical."}]},{"t":"p","runs":[{"text":"First, your operating system uses Python for its own work. On many Linux systems, parts of the package manager and desktop are written in it. Installing or upgrading packages into that Python can break things that have nothing to do with your project."}]},{"t":"p","runs":[{"text":"Second, and more common: two of your projects will eventually need different versions of the same package. Project A was written against version 1 and breaks on version 2. Project B needs version 2. There is one system Python and one slot per package, so one of them loses."}]},{"t":"p","runs":[{"text":"A "},{"text":"virtual environment","b":true},{"text":" is the fix. It is an ordinary folder containing its own "},{"text":"python","code":true},{"text":" and its own place to put packages. Install into it and nothing outside is touched. Delete the folder and the install is undone completely. Every project gets its own."}]},{"t":"h2","id":"making-one","runs":[{"text":"Making one"}]},{"t":"code","lang":"bash","label":"Bash","text":"cd my-project\npython3 -m venv .venv"},{"t":"p","runs":[{"text":"That creates a folder called "},{"text":".venv","code":true},{"text":". Now activate it, which means “for this terminal session, "},{"text":"python","code":true},{"text":" and "},{"text":"pip","code":true},{"text":" mean the ones inside "},{"text":".venv","code":true},{"text":"”:"}]},{"t":"code","lang":"bash","label":"Bash","text":"source .venv/bin/activate      # macOS or Linux\n.venv\\Scripts\\activate         # Windows PowerShell"},{"t":"p","runs":[{"text":"Your prompt changes to show "},{"text":"(.venv)","code":true},{"text":". Now install:"}]},{"t":"code","lang":"bash","label":"Bash","text":"python -m pip install requests"},{"t":"p","runs":[{"text":"When you are finished, "},{"text":"deactivate","code":true},{"text":" puts the terminal back to normal. Add "},{"text":".venv/","code":true},{"text":" to "},{"text":".gitignore","code":true},{"text":"; it is rebuildable and large, and it never belongs in a repository."}]},{"t":"p","runs":[{"text":"Use "},{"text":"python -m pip install","code":true},{"text":" rather than bare "},{"text":"pip install","code":true},{"text":". It guarantees the pip you run belongs to the python you are running, which removes the most common cause of the next section."}]},{"t":"h2","id":"the-error-that-will-happen-to-you","runs":[{"text":"The error that will happen to you"}]},{"t":"code","lang":"","label":"Text","text":"ModuleNotFoundError: No module named 'requests'"},{"t":"p","runs":[{"text":"This almost never means the install failed. It means the Python running your script is not the Python you installed into. Diagnose it from inside the program, not by guessing:"}]},{"t":"code","lang":"python","label":"Python","text":"import sys\nprint(sys.executable)"},{"t":"p","runs":[{"text":"If that prints a system path like "},{"text":"/usr/bin/python3","code":true},{"text":" and you installed into "},{"text":".venv","code":true},{"text":", there is your answer. Common causes: you opened a new terminal and forgot to activate, since activation only applies to one shell session; or your editor is configured to run a different interpreter than your terminal uses."}]},{"t":"p","runs":[{"text":"A related message you may see on Debian, Ubuntu or a Raspberry Pi:"}]},{"t":"code","lang":"","label":"Text","text":"error: externally-managed-environment"},{"t":"p","runs":[{"text":"That is not a bug. The system is refusing to let you install into the Python it depends on, and telling you to make a virtual environment. Make one."}]},{"t":"h2","id":"recording-what-a-project-needs","runs":[{"text":"Recording what a project needs"}]},{"t":"code","lang":"bash","label":"Bash","text":"python -m pip freeze > requirements.txt"},{"t":"p","runs":[{"text":"That writes every installed package and its exact version into a file. Someone else, or you on another machine, can then reproduce your setup:"}]},{"t":"code","lang":"bash","label":"Bash","text":"python3 -m venv .venv\nsource .venv/bin/activate\npython -m pip install -r requirements.txt"},{"t":"p","runs":[{"text":"Commit "},{"text":"requirements.txt","code":true},{"text":". It is small, it is text, and it is the difference between “works on my machine” and “works”."}]},{"t":"h2","id":"import-once-installed","runs":[{"text":"Import, once installed"}]},{"t":"code","lang":"python","label":"Python","text":"import requests\nprint(requests.__version__)\n\nfrom datetime import date\nprint(date.today())"},{"t":"p","runs":[{"text":"Installing and importing are separate steps. "},{"text":"pip install","code":true},{"text":" puts the code on your disk, once. "},{"text":"import","code":true},{"text":" loads it into a running program, and belongs at the top of every file that uses it."}]},{"t":"p","runs":[{"text":"One honest caution about PyPI: anyone can publish there, and names close to popular packages are sometimes registered by people hoping you will mistype. Check the spelling of a package before you install it, and prefer the name given in the official documentation over one you half-remember."}]},{"t":"h2","id":"try-this-now","runs":[{"text":"Try this now"}],"role":"try"},{"t":"p","runs":[{"text":"Make a folder, create a venv, activate it, install "},{"text":"requests","code":true},{"text":", then run a file containing "},{"text":"import sys, requests","code":true},{"text":" and "},{"text":"print(sys.executable)","code":true},{"text":". Then open a brand new terminal, do not activate, and run the same file. Read the error you get, and check it against what you now know."}]}],"check":{"question":[{"text":"You created "},{"text":".venv","code":true},{"text":", activated it, installed "},{"text":"requests","code":true},{"text":", and your script ran. The next day you open a fresh terminal, go to the same folder, run the same script, and get "},{"text":"ModuleNotFoundError: No module named 'requests'","code":true},{"text":". What is the most likely cause?"}],"options":[{"text":[{"text":"The install needed administrator rights and silently failed, so nothing was ever written to disk."}],"correct":false,"tempting":[{"text":"Permission problems are a genuine cause of failed installs, and reaching for sudo is folk advice that sometimes appears to work."}]},{"text":[{"text":"The fresh terminal is running the system Python, because activation applies only to the shell session you did it in."}],"correct":true,"tempting":null},{"text":[{"text":"requests","code":true},{"text":" was installed for one Python version and the script is being run by a different, older one."}],"correct":false,"tempting":[{"text":"Having several Pythons on one machine is real and does cause exactly this message, so it is a sound diagnosis that happens to be the wrong one here."}]},{"text":[{"text":"Only the file you tested in has the import; the package has to be imported in every file in the folder before it can be found."}],"correct":false,"tempting":[{"text":"Installing and importing both feel like ways of making a package available, so blurring the two leads to a plausible file-level explanation."}]}],"order":[3,0,1,2],"why":null},"prev":{"slug":"streaming-large-files","title":"Files larger than memory","minutes":8},"next":{"slug":"dependencies-and-pinning","title":"Pinning dependencies, so it still runs next year","minutes":8}}}