Building Your First Python Project in VS Code: A Beginner's Guide
There is a real difference between writing a Python file and building a Python project, and it is the step most tutorials skip. A file is one .py you run. A project is a folder with its own isolated dependencies, its code split into more than one place, and a record of what it needs to run somewhere else.
That difference is worth learning on something small, because every habit here scales directly to real work. We will build a unit converter — small enough to finish, structured enough to be a project.
What you need
- Python 3.9 or newer from python.org. On Windows, tick Add python.exe to PATH in the installer.
- VS Code, set up as in How to Use Visual Studio Code for Beginners
- The official Python extension by Microsoft
Check the install first:
python --version
If Windows opens the Microsoft Store instead, Python is not installed — use py in place of python throughout, or reinstall with PATH ticked.
Step 1: Make a project folder
Not a file. A folder.
mkdir unit-converter
cd unit-converter
code .
That last command opens VS Code in this folder. Everything — the explorer, search, the terminal, the settings — is now scoped to the project, which is what makes the rest of this work.
Step 2: Create a virtual environment
This is the step that separates a project from a script, and it is the one beginners most often skip.
A virtual environment is a private copy of Python for this project. Install a package inside it and it belongs to this project alone. Without one, every package you ever install piles into a single system-wide Python, and two projects needing different versions of the same library become impossible to have at once.
python -m venv .venv
Activate it:
# Windows (PowerShell)
.venv\Scripts\Activate.ps1
# macOS / Linux
source .venv/bin/activate
Your prompt now starts with (.venv). That prefix is the whole point — it tells you which Python you are about to run.
Tell VS Code about it too. Open the Command Palette with Ctrl + Shift + P, run Python: Select Interpreter, and choose the one inside .venv. Skipping this is why a beginner's editor shows import errors for packages that are definitely installed.
If PowerShell refuses to run the activate script, it is the execution policy. Once, per user:
Set-ExecutionPolicy -Scope CurrentUser RemoteSigned
Step 3: Split the code
Create two files. The split is the point — this is what makes it a project.
converter.py holds the logic and knows nothing about the user:
"""Unit conversion logic."""
CONVERSIONS = {
("km", "miles"): lambda v: v * 0.621371,
("miles", "km"): lambda v: v / 0.621371,
("c", "f"): lambda v: v * 9 / 5 + 32,
("f", "c"): lambda v: (v - 32) * 5 / 9,
("kg", "lb"): lambda v: v * 2.20462,
("lb", "kg"): lambda v: v / 2.20462,
}
def convert(value: float, source: str, target: str) -> float:
"""Convert a value between two units.
Raises ValueError if the pair is not supported.
"""
key = (source.lower(), target.lower())
if key not in CONVERSIONS:
raise ValueError(f"Cannot convert {source} to {target}")
return CONVERSIONS[key](value)
def supported_pairs() -> list[str]:
return [f"{a} -> {b}" for a, b in CONVERSIONS]
main.py handles the person using it and knows nothing about the maths:
"""Command-line interface for the converter."""
from converter import convert, supported_pairs
def main() -> None:
print("Unit converter. Supported conversions:")
for pair in supported_pairs():
print(f" {pair}")
try:
value = float(input("\nValue: "))
except ValueError:
print("That is not a number.")
return
source = input("From unit: ").strip()
target = input("To unit: ").strip()
try:
result = convert(value, source, target)
except ValueError as error:
print(error)
return
print(f"\n{value} {source} = {result:.2f} {target}")
if __name__ == "__main__":
main()
Two things there are worth pausing on.
if __name__ == "__main__": means the code below it runs when you execute this file directly, but not when another file imports it. That is what lets you reuse converter.py from a test or a web app later without it trying to prompt someone.
And the try/except blocks: anything a person types is untrusted. float() raises on "abc", and the program should say so rather than print a stack trace.
Step 4: Run it
python main.py
Unit converter. Supported conversions:
km -> miles
miles -> km
c -> f
f -> c
kg -> lb
lb -> kg
Value: 100
From unit: km
To unit: miles
100.0 km = 62.14 miles
Try it with nonsense — a letter for the value, or km to kg. It should explain itself rather than crash. A program that fails politely is most of what separates a beginner's script from something usable.
Step 5: Record the dependencies
This project has none yet, which makes it the perfect moment to learn the habit.
pip freeze > requirements.txt
That file lists exactly what the project needs. Anyone cloning it — including you, on another machine, in six months — can reproduce your environment:
pip install -r requirements.txt
Regenerate it whenever you add a package. A project whose dependencies live only in your head runs on exactly one computer.
Step 6: Keep the environment out of version control
If you use git, create a .gitignore before your first commit:
.venv/
__pycache__/
*.pyc
.venv is thousands of files, specific to your operating system, and reconstructible from requirements.txt. Committing it is one of the most common first-project mistakes.
What you ended up with
unit-converter/
├── .venv/ (ignored)
├── .gitignore
├── converter.py logic, no I/O
├── main.py I/O, no logic
└── requirements.txt
That shape — isolated environment, logic separated from interface, dependencies written down, environment excluded from the repository — is the same shape as a serious Python project. Everything after this is more of it.
Common problems
ModuleNotFoundError for something you installed. The editor and the terminal are using different Pythons. Confirm with python -c "import sys; print(sys.executable)" and re-run Python: Select Interpreter.
cannot be loaded because running scripts is disabled. PowerShell's execution policy. Run the Set-ExecutionPolicy command above once.
Changes not taking effect. The file was not saved. Turn on Auto Save in settings and stop thinking about it.
ImportError: cannot import name 'convert'. main.py and converter.py must be in the same folder, and the terminal must be running from that folder.
Where to go next
Three natural extensions, in increasing order of effort: add more unit pairs to the CONVERSIONS dictionary, write a test file that checks convert() returns what you expect, or replace main.py with a small web interface while keeping converter.py untouched. That last one is the payoff for separating them.
Frequently Asked Questions
What is a virtual environment and do I really need one?
It is a private Python installation for one project, so its packages cannot collide with another project's. You can skip it for a five-line script. The moment you install a package, you want one — otherwise two projects needing different versions of the same library cannot coexist on your machine.
Why split the code into two files for such a small program?
To separate logic from interaction. converter.py can be imported by a test, a web app or another script; main.py is one way of using it. Learning that split on something trivial is much easier than retrofitting it later.
What does `if __name__ == "__main__":` actually do?
It runs the code beneath it only when the file is executed directly, not when it is imported. Without it, importing main.py from a test would immediately start prompting for input.
Should I commit the .venv folder to git?
No. It is large, platform-specific, and rebuildable from requirements.txt. Add .venv/ to .gitignore before your first commit.
Why does my program crash when I type a letter instead of a number?
float() raises a ValueError on input it cannot parse. Wrapping the call in try/except ValueError lets you print a useful message instead of a stack trace — that is what the example above does.
Related Tools & Apps
Memory Allocator
SimulatorVisualize heap memory allocation strategies — First Fit, Best Fit, and Worst Fit…
Base64 Encoder / Decoder
ToolEncode text to Base64 or decode Base64 strings back to plain text.
JavaScript Error Handling
LabMaster try/catch, error types, custom errors, and debugging strategies with inte…
Regex Lab
AppBuild and debug regular expressions with live match highlighting, a plain-Englis…
Intro to HTML
LabLearn the building blocks of the web — write your first HTML elements and see th…
Cryptogram
GameDecode the secret message by cracking the substitution cipher!
Related Posts
Lessons From Building Digital Creations
Across this site there are [301 tools](/tools/), [90 games](/games/), [35 labs](/labs/), [21 apps](/…
Quick Guide to Installing Linux as an Alternative to Windows
Installing Ubuntu alongside Windows takes about forty minutes, and roughly thirty-five of those are …
A Practical Guide to Using ChatGPT and Gemini for Everyday Tasks
Most advice about using AI assistants stops at "you can use it to draft emails", which is true and u…