Python · lesson 2 of 34
Beginner
16- 1 Introduction to Python
- 2 Setting Up Python
- 3 Python Variables and Type System
- 4 Python Data Types
- 5 Python Operators
- 6 Python Strings
- 7 Control Flow in Python
- 8 Python Functions and Parameters
- 9 Python Data Structures
- 10 Python Collections
- 11 Python Modules and Packages
- 12 Object-Oriented Programming in Python
- 13 Encapsulation and Name Mangling in Python
- 14 Polymorphism and Duck Typing in Python
- 15 Abstraction with Abstract Base Classes in Python
- 21 Building a Python CLI Tool
Intermediate
12- 16 Multiple Inheritance and MRO in Python
- 17 Composition vs Inheritance in Python
- 18 Python Dataclasses
- 19 Error Handling in Python
- 20 File I/O, pathlib, and JSON in Python
- 22 Python Decorators and Closures
- 23 Python Generators
- 24 Python Context Managers
- 25 Python Concurrency
- 27 Testing Python Code
- 28 Python Security
- 34 Python Interview Prep
Advanced
6Setting Up Python
Install Python, create and activate a virtual environment, install and freeze packages with pip, and run a first script, with real command output.
By SkillByExample · Updated
Setting up Python well is three steps: install a current Python 3, create a virtual environment for each project, and install packages into it with pip. The installer commands differ by operating system; everything after that is the same everywhere. The workflow commands below were run on Linux with Python 3.13.
Installing Python
These are the standard install commands for each platform — run the one for yours. (They are reference commands, not run as part of this lesson.)
Windows: download the installer from python.org/downloads and tick Add python.exe to PATH; or use winget install Python.Python.3.13. The py launcher then picks a version: py -3.13.
macOS: brew install python, or the python.org installer. The python3 that Apple’s developer tools provide is fine for scripts but lags behind current releases.
Debian/Ubuntu:
sudo apt update
sudo apt install python3 python3-venv python3-pip
python3-venv is the package beginners most often miss — without it, python3 -m venv fails.
Several versions side by side: pyenv (macOS/Linux) or uv python install 3.13 manage multiple interpreters per project.
Whichever route you took, check what you got:
$ python3 --version
Python 3.13.16
$ python3 -c "import sys; print(sys.executable)"
/usr/bin/python3
sys.executable shows which installation the python3 command actually runs — the first thing to check when “it works in one terminal but not another”.
Creating a virtual environment
A virtual environment is a folder holding a private copy of the interpreter’s site-packages, so each project’s packages stay separate.
$ python3 -m venv .venv
$ ls .venv
bin
include
lib
lib64
pyvenv.cfg
$ source .venv/bin/activate && which python && python -c "import sys; print(sys.prefix != sys.base_prefix)"
/home/user/py-demo/setup/.venv/bin/python
True
After source .venv/bin/activate, python and pip resolve to the copies inside .venv, and sys.prefix differs from sys.base_prefix — that’s how Python knows it’s in a venv. Your shell prompt also gains a (.venv) prefix. On Windows the activate script is .venv\Scripts\Activate.ps1 (PowerShell) and the folder is Scripts instead of bin. Run deactivate to leave.
You don’t have to activate at all — calling the venv’s interpreter directly is equivalent and is what scripts and CI usually do:
$ .venv/bin/python -m pip --version
pip 26.2.1 from /home/user/py-demo/setup/.venv/lib/python3.13/site-packages/pip (python 3.13)
Installing and freezing packages
Install into the venv with python -m pip, then record exactly what got installed.
$ .venv/bin/python -m pip install -q "requests==2.32.3"
$ .venv/bin/python -m pip freeze
certifi==2026.7.22
charset-normalizer==3.5.2
idna==3.20
requests==2.32.3
urllib3==2.8.0
$ .venv/bin/python -m pip freeze > requirements.txt
$ .venv/bin/python -c "import requests; print(requests.__version__)"
2.32.3
You asked for one package and got five: freeze lists requests’ own dependencies too, each pinned to the exact version installed today. That file lets anyone recreate this environment with python -m pip install -r requirements.txt. Pinning == in an application’s requirements prevents a surprise upgrade from breaking it.
Proving the isolation
Packages installed in the venv are invisible to other interpreters.
$ python3 -m venv other-env
$ other-env/bin/python -c "import requests"
Traceback (most recent call last):
File "<string>", line 1, in <module>
import requests
ModuleNotFoundError: No module named 'requests'
other-env is a second project’s environment: it has never heard of requests. That separation is the point — two projects can need different versions of the same library without conflict. It’s also the most common “but I installed it!” confusion: the package went into a different environment than the one running your code.
Ignoring the venv in git
The environment is rebuilt from requirements.txt, so it never belongs in version control.
# .gitignore
.venv/
__pycache__/
*.pyc
.env
Your first script
A script with a type hint, a docstring and the __main__ guard — the shape most Python files take.
def greet(name: str) -> str:
"""Return a greeting for the given name."""
return f"Hello, {name}!"
if __name__ == "__main__":
name = input("Enter your name: ")
print(greet(name))
$ echo "Alice" | python hello.py
Enter your name: Hello, Alice!
The input was piped in, so “Alice” doesn’t appear on screen the way it would when you type it — the prompt and the greeting run together on one line. Run python hello.py in a terminal and type the name to see the interactive version.
The REPL
Running python with no file starts the interactive interpreter, which evaluates each line and prints the result.
$ printf '2 + 2\n"hello".upper()\n[x**2 for x in range(5)]\n' | python -i -q
>>> 4
>>> 'HELLO'
>>> [0, 1, 4, 9, 16]
>>>
Here the lines were piped in, so they aren’t echoed after each >>> prompt; typed interactively, you’d see >>> 2 + 2 followed by 4. The REPL shows the repr of each result — note the quotes around 'HELLO', which print would omit. Exit with exit() or Ctrl-D (Ctrl-Z then Enter on Windows).
Editor setup (VS Code)
Install the Python extension (it brings Pylance), then run Python: Select Interpreter from the command palette and choose .venv. If you skip that step the editor uses some other Python and flags every installed package as missing. A minimal .vscode/settings.json with the Ruff extension for formatting and linting:
{
"python.defaultInterpreterPath": "${workspaceFolder}/.venv/bin/python",
"[python]": {
"editor.defaultFormatter": "charliermarsh.ruff",
"editor.formatOnSave": true
}
}
Common setup mistakes
- Installing without a venv — packages land in a shared location and versions collide.
pipandpythonfrom different installs — usepython -m pipso they always match.- Committing
.venv/— commitrequirements.txtorpyproject.tomlinstead. - Forgetting to freeze — without pinned versions, a collaborator’s install can differ from yours.
Practice
1. Create a venv called demo-env, and print the path of its Python and whether it’s a venv, without activating it.
Solution
$ python3 -m venv demo-env
$ demo-env/bin/python -c "import sys; print(sys.executable); print(sys.prefix != sys.base_prefix)"
/home/user/py-demo/setup/demo-env/bin/python
True
Calling the venv’s own interpreter uses that environment directly — activation only changes which python your shell finds first.
2. In demo-env, install six==1.16.0, freeze it into requirements.txt, then build a second venv from that file and confirm the version.
Solution
$ demo-env/bin/python -m pip install -q "six==1.16.0"
$ demo-env/bin/python -m pip freeze > requirements.txt
$ cat requirements.txt
six==1.16.0
$ python3 -m venv rebuilt && rebuilt/bin/python -m pip install -q -r requirements.txt
$ rebuilt/bin/python -c "import six; print(six.__version__)"
1.16.0
six has no dependencies, so the frozen file has a single line. The rebuilt environment matches exactly.
3. Change hello.py so it greets a name passed on the command line (python hello.py Bo), falling back to "world" when none is given.
Solution
import sys
def greet(name: str) -> str:
return f"Hello, {name}!"
if __name__ == "__main__":
name = sys.argv[1] if len(sys.argv) > 1 else "world"
print(greet(name))
$ python hello_args.py Bo
Hello, Bo!
$ python hello_args.py
Hello, world!
sys.argv[0] is the script name, so the first real argument is sys.argv[1].