Python for Newbies Your Ultimate Guide to Learning Python and Best Practices

Updated: March 27, 2026

Python for Newbies Your Ultimate Guide to Learning Python and Best Practices

TL;DR

Start Python with Python 3.12+, use virtual environments (uv or venv) from day one, follow modern tooling (ruff for linting, pyright for type checking), and write code with type hints for clarity. These practices prevent bad habits and scale smoothly from hobby projects to professional code.

Learning Python is one thing. Learning it right is another. Too many tutorials teach quick-and-dirty habits: no type hints, no linting, no structure. Then learners jump into real projects and struggle with cryptic errors, hard-to-debug code, and deprecated practices they learned years ago. This guide teaches Python fundamentals while embedding best practices from day one — so your code is clean, readable, and professional from your first script.

Step 1: Install Python 3.12+ (Not 2, Not Older 3.x)

Python 3.12 brings better error messages, performance improvements, and optimized bytecode. Match statements (structural pattern matching) were introduced in Python 3.10. Don't use Python 2 (end-of-life 2020) or older Python 3.x versions (outdated). Always choose the latest stable version.

On Windows

  1. Visit python.org/downloads
  2. Download Python 3.12 (or latest 3.x)
  3. CHECK "Add Python to PATH" before installing
  4. Verify: Open Command Prompt, run python --version

On macOS

# Using Homebrew (install brew first from brew.sh)
brew install python@3.12

On Linux (Ubuntu/Debian)

sudo apt update
sudo apt install python3.12 python3.12-venv

Step 2: Set Up a Virtual Environment (Critical!)

Never code directly in your system Python. Virtual environments isolate project dependencies so one project's libraries don't break another's. Use uv (faster, simpler) or venv (standard library).

# Install uv
curl -LsSf https://astral.sh/uv/install.sh | sh

# Create a project directory
mkdir my_python_project
cd my_python_project

# Initialize a virtual environment
uv venv
source .venv/bin/activate  # On Windows: .venv\Scripts\activate

Using venv (Standard, Built-in)

mkdir my_python_project
cd my_python_project
python -m venv venv
source venv/bin/activate  # On Windows: venv\Scripts\activate

Your terminal prompt now shows (.venv) $ indicating the environment is active.

Step 3: Modern Tooling Stack (2026 Standard)

Code Formatter: Ruff

Ruff enforces consistent code style automatically. Install it:

uv pip install ruff
# or with pip: pip install ruff

Create a pyproject.toml file in your project root:

[tool.ruff]
line-length = 100
target-version = "py312"

[tool.ruff.lint]
select = ["E", "F", "W"]  # Errors, undefined names, whitespace

Format your code:

ruff format .

Ruff automatically fixes spacing, import order, and style violations.

Type Checker: Pyright

Pyright catches type errors before runtime. Install:

uv pip install pyright

Now write code with type hints:

def calculate_total(price: float, quantity: int) -> float:
    """Calculate order total"""
    return price * quantity

result = calculate_total(19.99, 5)  # OK
bad = calculate_total("19.99", 5)   # Error: string ≠ float

Run pyright:

pyright

It catches the type error instantly without running the code.

IDE: VS Code with Python Extension

Download VS Code for free. Install the Python extension (open VS Code, go to Extensions, search "Python", install Microsoft's).

Configure VS Code for our tooling stack by creating .vscode/settings.json:

{
  "python.linting.enabled": true,
  "python.linting.ruffEnabled": true,
  "[python]": {
    "editor.defaultFormatter": "charliermarsh.ruff",
    "editor.formatOnSave": true,
    "editor.codeActionsOnSave": {
      "source.organizeImports": "explicit"
    }
  },
  "python.analysis.typeCheckingMode": "strict"
}

Now VS Code auto-formats code on save and shows type errors in real-time.

Core Python Syntax with Type Hints

Variables and Types

# Type hints make intent clear
name: str = "Alice"
age: int = 30
height: float = 5.9
is_student: bool = False

# Collections with specific types
scores: list[int] = [95, 87, 92]
person: dict[str, int] = {"age": 30, "year": 2026}

Type hints cost nothing at runtime and improve readability massively. They're not optional — they're a best practice.

Functions with Type Hints

def greet(name: str, age: int) -> str:
    """Return a personalized greeting

    Args:
        name: Person's name
        age: Person's age

    Returns:
        Formatted greeting string
    """
    return f"{name} is {age} years old"

greeting = greet("Bob", 25)

Every function should declare input types and return type. This prevents bugs and makes code self-documenting.

Modern Pattern Matching (Python 3.10+)

Python 3.10 introduced match statements (like switch in other languages):

def describe_number(n: int) -> str:
    match n:
        case 0:
            return "Zero"
        case 1 | 2:  # 1 or 2
            return "Small"
        case n if n < 0:
            return "Negative"
        case _:  # Default
            return "Large"

Much cleaner than chained if/elif/else.

List Comprehensions (Pythonic Way)

# Long way (avoid)
squared = []
for num in range(10):
    squared.append(num ** 2)

# Pythonic way
squared = [num ** 2 for num in range(10)]

# With conditions
evens = [x for x in range(20) if x % 2 == 0]

Comprehensions are faster and more readable.

Project Structure: Professional Layout

Organize your project like real code:

my_project/
├── .venv/                  # Virtual environment
├── pyproject.toml          # Project config (ruff, dependencies)
├── src/
│   └── my_project/
│       ├── __init__.py
│       ├── main.py
│       └── utils.py
├── tests/
│   ├── __init__.py
│   └── test_utils.py
├── .gitignore
└── README.md

This structure scales from hobby project to professional codebase. The __init__.py files (even empty) tell Python these are packages.

Managing Dependencies Properly

Using uv

# Add a dependency
uv pip install requests

# Create a requirements file automatically
uv pip freeze > requirements.txt

Or declare in pyproject.toml:

[project]
dependencies = [
    "requests>=2.31.0",
    "pandas>=2.0.0"
]

Then install:

uv pip install -e .

Testing: Write Tests from Day One

Testing prevents bugs and makes refactoring safe:

# src/my_project/math_utils.py
def add(a: int, b: int) -> int:
    return a + b
# tests/test_math_utils.py
from my_project.math_utils import add

def test_add():
    assert add(2, 3) == 5
    assert add(-1, 1) == 0
    assert add(0, 0) == 0

Run tests:

uv pip install pytest
pytest

Small test habits now prevent large disasters later.

Common Beginner Mistakes (And How to Avoid Them)

1. Using Global Variables

# WRONG: Global counter
counter = 0
def increment():
    global counter  # Ugly and buggy
    counter += 1

# RIGHT: Return values
def increment(counter: int) -> int:
    return counter + 1

Functions should be independent, not rely on global state.

2. Magic Numbers Without Explanation

# WRONG: What does 0.08 mean?
tax = price * 0.08

# RIGHT: Named constant
TAX_RATE = 0.08
tax = price * TAX_RATE

Constants with descriptive names make intent clear.

3. Ignoring Edge Cases

# WRONG: No error handling
def divide(a: float, b: float) -> float:
    return a / b

# RIGHT: Handle division by zero
def divide(a: float, b: float) -> float | None:
    if b == 0:
        return None
    return a / b

Professional code anticipates what can go wrong.

4. Not Using Docstrings

# WRONG: Unclear
def calc(x, y):
    return x * y + x / y

# RIGHT: Clear intent
def calculate_avg_rate(price: float, quantity: int) -> float:
    """Calculate average price per unit.

    Args:
        price: Total price in dollars
        quantity: Number of units

    Returns:
        Average price per unit
    """
    return price / quantity

Future you will thank present you for documenting intent.

Practical Project: Todo List App with Best Practices

Let's build a real project using everything learned:

# src/todoapp/main.py
from typing import Optional
from pathlib import Path
import json

class TodoList:
    """Simple todo list manager"""

    def __init__(self, file_path: Path = Path("todos.json")):
        self.file_path = file_path
        self.todos: list[dict[str, str]] = self._load()

    def _load(self) -> list[dict[str, str]]:
        """Load todos from file"""
        if self.file_path.exists():
            with open(self.file_path) as f:
                return json.load(f)
        return []

    def add(self, task: str) -> None:
        """Add a new todo"""
        self.todos.append({
            "task": task,
            "done": False
        })
        self._save()

    def mark_done(self, index: int) -> bool:
        """Mark todo as complete"""
        if 0 <= index < len(self.todos):
            self.todos[index]["done"] = True
            self._save()
            return True
        return False

    def _save(self) -> None:
        """Save todos to file"""
        with open(self.file_path, 'w') as f:
            json.dump(self.todos, f, indent=2)

    def list_all(self) -> None:
        """Display all todos"""
        for i, todo in enumerate(self.todos, 1):
            status = "✓" if todo["done"] else "○"
            print(f"{i}. {status} {todo['task']}")

if __name__ == "__main__":
    app = TodoList()
    app.add("Learn Python")
    app.add("Build a project")
    app.list_all()

This code has:

  • Type hints throughout
  • Docstrings for every method
  • Error handling
  • File I/O
  • Proper naming conventions
  • Testable structure

Learning Paths by Goal

Goal: AI/ML Career

  1. Master Python fundamentals (this guide)
  2. Learn NumPy, Pandas, Scikit-learn
  3. Study linear algebra and statistics
  4. Build 3–5 ML projects for portfolio

Goal: Web Development

  1. Python fundamentals
  2. FastAPI or Django framework
  3. SQL and databases
  4. Deploy to cloud (AWS, GCP, Heroku)

Goal: Automation/Scripting

  1. Python fundamentals
  2. File I/O and regex
  3. APIs and web scraping (with ethics in mind)
  4. Task scheduling (cron, APScheduler)

Resources

  • Official Python Docs: docs.python.org/3
  • Real Python: Comprehensive, well-written tutorials
  • Type Hints Guide: mypy.readthedocs.io
  • PEP 8 Style Guide: Python's official code style (PEP = Python Enhancement Proposal)

Conclusion

Learning Python properly means starting with best practices, not learning them later. Virtual environments isolate projects, type hints prevent bugs, linting ensures consistency, and proper structure scales from scripts to applications. It takes 10 minutes longer to set up correctly, but saves hours of debugging later. Invest in the right habits now, and your code will remain clean and professional as you grow from beginner to developer.


FREE WEEKLY NEWSLETTER

Stay on the Nerd Track

One email per week — courses, deep dives, tools, and AI experiments.

No spam. Unsubscribe anytime.