Python Phase 1: Fundamentals - Getting Started with Python

Python Phase 1: Fundamentals - Getting Started with Python
Welcome to Phase 1 of the Python Learning Roadmap! This phase will take you from zero to comfortable with Python's core syntax and fundamental programming constructs. Whether you're coming from another language or starting fresh, by the end of this phase you'll be writing Python code confidently.
What You'll Learn
✅ Python installation and IDE setup
✅ Python syntax basics and data types
✅ Control flow with if/else, match/case, and loops
✅ Functions with parameters (*args, **kwargs)
✅ Lists, tuples, dictionaries, and sets
✅ String manipulation and f-strings
✅ Exception handling basics
✅ Virtual environments with venv
Prerequisites
- Programming experience: Familiarity with variables, loops, and functions in any language
- Command line basics: Comfort with terminal/command prompt
- Time commitment: 2 weeks, 10-15 hours total
Installing Python 3.10+
Download and Install
Python 3.10+ includes modern features like structural pattern matching (match/case) and improved type hints.
macOS/Linux:
# Check if Python is installed
python3 --version
# Install via Homebrew (macOS)
brew install python@3.12
# Install via apt (Ubuntu/Debian)
sudo apt update
sudo apt install python3.12Windows:
- Download from python.org
- Run installer and check "Add Python to PATH"
- Verify:
python --version
IDE Setup
VS Code (Recommended):
# Install VS Code extensions
code --install-extension ms-python.python
code --install-extension ms-python.vscode-pylancePyCharm:
- Download PyCharm Community Edition (free)
- Excellent for beginners with built-in type checking and debugging
Python Syntax Basics
Variables and Data Types
Python uses dynamic typing - no need to declare types explicitly.
# Variables (snake_case naming)
name: str = "Alice"
age: int = 30
height: float = 5.7
is_student: bool = False
# Type hints are optional but recommended
user_id: int = 12345
email: str = "alice@example.com"
# Multiple assignment
x, y, z = 1, 2, 3Basic Data Types
# Integers
count: int = 100
negative: int = -50
# Floats
price: float = 19.99
scientific: float = 1.5e-4
# Strings
message: str = "Hello, Python!"
multiline: str = """
This is a
multiline string
"""
# Booleans
is_active: bool = True
has_permission: bool = False
# None (null equivalent)
result: str | None = NoneOperators
# Arithmetic
x = 10 + 5 # 15
y = 10 - 5 # 5
z = 10 * 5 # 50
w = 10 / 5 # 2.0 (always returns float)
q = 10 // 3 # 3 (floor division)
r = 10 % 3 # 1 (modulo)
p = 2 ** 3 # 8 (exponentiation)
# Comparison
10 == 10 # True (equality)
10 != 5 # True (inequality)
10 > 5 # True
10 >= 10 # True
10 < 20 # True
10 <= 10 # True
# Logical
True and False # False
True or False # True
not True # False
# Identity
x is None # Check if x is None
x is not None # Check if x is not NoneControl Flow
If/Else Statements
age: int = 18
if age >= 18:
print("Adult")
elif age >= 13:
print("Teenager")
else:
print("Child")
# Ternary operator
status: str = "Adult" if age >= 18 else "Minor"
# Truthiness
name: str = "Alice"
if name: # Non-empty strings are truthy
print(f"Hello, {name}")
# Check for None
result: str | None = None
if result is None:
print("No result")Match/Case (Python 3.10+)
Python's structural pattern matching is more powerful than traditional switch statements.
def handle_status(status_code: int) -> str:
match status_code:
case 200:
return "Success"
case 404:
return "Not Found"
case 500:
return "Server Error"
case _: # Default case
return "Unknown"
# Pattern matching with values
def describe_point(point: tuple[int, int]) -> str:
match point:
case (0, 0):
return "Origin"
case (0, y):
return f"On Y-axis at {y}"
case (x, 0):
return f"On X-axis at {x}"
case (x, y):
return f"Point at ({x}, {y})"Loops
For loops:
# Iterate over a range
for i in range(5): # 0, 1, 2, 3, 4
print(i)
# Iterate over a list
fruits: list[str] = ["apple", "banana", "cherry"]
for fruit in fruits:
print(fruit)
# Enumerate (index + value)
for index, fruit in enumerate(fruits):
print(f"{index}: {fruit}")
# Iterate over range with step
for i in range(0, 10, 2): # 0, 2, 4, 6, 8
print(i)While loops:
count: int = 0
while count < 5:
print(count)
count += 1
# Break and continue
for i in range(10):
if i == 3:
continue # Skip 3
if i == 7:
break # Stop at 7
print(i)Functions
Basic Functions
def greet(name: str) -> str:
"""Greet a person by name."""
return f"Hello, {name}!"
# Call function
message: str = greet("Alice")
print(message) # "Hello, Alice!"
# Function with default parameter
def greet_with_title(name: str, title: str = "Mr.") -> str:
return f"Hello, {title} {name}!"
print(greet_with_title("Smith")) # "Hello, Mr. Smith!"
print(greet_with_title("Smith", "Dr.")) # "Hello, Dr. Smith!"Multiple Return Values
def get_user_info() -> tuple[str, int, str]:
"""Return multiple values as a tuple."""
return "Alice", 30, "alice@example.com"
# Unpack return values
name, age, email = get_user_info()
print(f"{name} is {age} years old")*args and **kwargs
# *args: Variable positional arguments
def sum_numbers(*args: int) -> int:
"""Sum any number of integers."""
return sum(args)
print(sum_numbers(1, 2, 3)) # 6
print(sum_numbers(1, 2, 3, 4, 5)) # 15
# **kwargs: Variable keyword arguments
def print_user_info(**kwargs: str | int) -> None:
"""Print user information."""
for key, value in kwargs.items():
print(f"{key}: {value}")
print_user_info(name="Alice", age=30, city="NYC")
# name: Alice
# age: 30
# city: NYC
# Combined usage
def create_user(name: str, *tags: str, **metadata: str | int) -> dict:
"""Create user with tags and metadata."""
return {
"name": name,
"tags": list(tags),
"metadata": metadata
}
user = create_user(
"Alice",
"developer",
"python",
age=30,
city="NYC"
)Data Structures
Lists (Mutable, Ordered)
# Create lists
numbers: list[int] = [1, 2, 3, 4, 5]
fruits: list[str] = ["apple", "banana", "cherry"]
mixed: list[int | str] = [1, "two", 3, "four"]
# Access elements
first: str = fruits[0] # "apple"
last: str = fruits[-1] # "cherry"
# Slicing
first_two: list[str] = fruits[0:2] # ["apple", "banana"]
last_two: list[str] = fruits[-2:] # ["banana", "cherry"]
# Modify lists
fruits.append("orange") # Add to end
fruits.insert(1, "mango") # Insert at index
fruits.remove("banana") # Remove first occurrence
popped: str = fruits.pop() # Remove and return last item
# List methods
numbers = [3, 1, 4, 1, 5, 9, 2, 6]
numbers.sort() # Sort in place
numbers.reverse() # Reverse in place
count: int = numbers.count(1) # Count occurrences
# Check membership
if "apple" in fruits:
print("Found apple!")Tuples (Immutable, Ordered)
# Create tuples
point: tuple[int, int] = (10, 20)
rgb: tuple[int, int, int] = (255, 128, 0)
# Unpack tuples
x, y = point
red, green, blue = rgb
# Named tuples (lightweight data classes)
from typing import NamedTuple
class Point(NamedTuple):
x: int
y: int
p = Point(10, 20)
print(p.x, p.y) # 10 20Dictionaries (Key-Value Pairs)
# Create dictionaries
user: dict[str, str | int] = {
"name": "Alice",
"age": 30,
"email": "alice@example.com"
}
# Access values
name: str = user["name"] # Raises KeyError if missing
age: int | None = user.get("age") # Returns None if missing
age_default: int = user.get("age", 0) # Returns default
# Modify dictionaries
user["city"] = "NYC" # Add/update key
del user["email"] # Delete key
popped_value = user.pop("age", None) # Remove and return
# Iterate over dictionaries
for key in user:
print(f"{key}: {user[key]}")
for key, value in user.items():
print(f"{key}: {value}")
# Dictionary comprehension
squares: dict[int, int] = {x: x**2 for x in range(5)}
# {0: 0, 1: 1, 2: 4, 3: 9, 4: 16}Sets (Unique, Unordered)
# Create sets
fruits: set[str] = {"apple", "banana", "cherry"}
numbers: set[int] = {1, 2, 3, 4, 5}
# Sets automatically remove duplicates
numbers = {1, 2, 2, 3, 3, 3} # {1, 2, 3}
# Add and remove
fruits.add("orange")
fruits.remove("banana") # Raises KeyError if missing
fruits.discard("banana") # No error if missing
# Set operations
a: set[int] = {1, 2, 3, 4}
b: set[int] = {3, 4, 5, 6}
union: set[int] = a | b # {1, 2, 3, 4, 5, 6}
intersection: set[int] = a & b # {3, 4}
difference: set[int] = a - b # {1, 2}
symmetric_diff: set[int] = a ^ b # {1, 2, 5, 6}String Manipulation
String Basics
# Create strings
name: str = "Alice"
message: str = 'Hello, World!'
multiline: str = """
Line 1
Line 2
"""
# String concatenation
full_name: str = "Alice" + " " + "Smith"
# String repetition
separator: str = "-" * 20 # "--------------------"
# String methods
text: str = " Hello, Python! "
lower: str = text.lower() # " hello, python! "
upper: str = text.upper() # " HELLO, PYTHON! "
stripped: str = text.strip() # "Hello, Python!"
replaced: str = text.replace("Python", "World")F-Strings (Formatted Strings)
name: str = "Alice"
age: int = 30
# Basic f-string
message: str = f"My name is {name} and I'm {age} years old"
# Expressions in f-strings
result: str = f"Next year I'll be {age + 1}"
# Format numbers
price: float = 19.99
formatted: str = f"Price: ${price:.2f}" # "Price: $19.99"
# Align text
item: str = "Apple"
count: int = 5
line: str = f"{item:<10} {count:>5}" # "Apple 5"
# Debug mode (Python 3.8+)
x: int = 10
debug: str = f"{x=}" # "x=10"String Operations
# Slicing
text: str = "Python"
first_three: str = text[:3] # "Pyt"
last_three: str = text[-3:] # "hon"
# Split and join
sentence: str = "Hello, World, Python"
words: list[str] = sentence.split(", ") # ["Hello", "World", "Python"]
joined: str = " | ".join(words) # "Hello | World | Python"
# Check content
text = "Hello123"
text.isalpha() # False (contains numbers)
text.isdigit() # False (contains letters)
text.isalnum() # True (alphanumeric)
# Startswith/Endswith
filename: str = "document.pdf"
if filename.endswith(".pdf"):
print("It's a PDF!")File I/O Basics
Reading Files
# Read entire file
with open("data.txt", "r") as file:
content: str = file.read()
print(content)
# Read line by line
with open("data.txt", "r") as file:
for line in file:
print(line.strip())
# Read all lines into list
with open("data.txt", "r") as file:
lines: list[str] = file.readlines()Writing Files
# Write to file (overwrites)
with open("output.txt", "w") as file:
file.write("Hello, World!\n")
file.write("Second line\n")
# Append to file
with open("output.txt", "a") as file:
file.write("Appended line\n")
# Write multiple lines
lines: list[str] = ["Line 1\n", "Line 2\n", "Line 3\n"]
with open("output.txt", "w") as file:
file.writelines(lines)Working with Paths
from pathlib import Path
# Create Path object
file_path = Path("data/input.txt")
# Check existence
if file_path.exists():
print("File exists!")
# Read with Path
content: str = file_path.read_text()
# Write with Path
file_path.write_text("Hello, World!")
# Get file info
print(file_path.name) # "input.txt"
print(file_path.stem) # "input"
print(file_path.suffix) # ".txt"
print(file_path.parent) # Path("data")Exception Handling
Try/Except Basics
# Basic exception handling
try:
number: int = int("abc") # ValueError
except ValueError:
print("Invalid number!")
# Handle multiple exceptions
try:
result: int = 10 / 0
except ZeroDivisionError:
print("Cannot divide by zero!")
except ValueError:
print("Invalid value!")
# Catch all exceptions (use sparingly)
try:
# risky operation
pass
except Exception as e:
print(f"Error occurred: {e}")Finally and Else
# Finally: Always executes
try:
file = open("data.txt", "r")
content = file.read()
except FileNotFoundError:
print("File not found!")
finally:
if 'file' in locals():
file.close()
# Else: Executes if no exception
try:
result: int = 10 / 2
except ZeroDivisionError:
print("Error!")
else:
print(f"Result: {result}") # Executes
finally:
print("Cleanup") # Always executesRaising Exceptions
def divide(a: int, b: int) -> float:
"""Divide two numbers."""
if b == 0:
raise ValueError("Cannot divide by zero!")
return a / b
# Custom exception
class InvalidAgeError(Exception):
"""Raised when age is invalid."""
pass
def set_age(age: int) -> None:
if age < 0:
raise InvalidAgeError("Age cannot be negative!")
print(f"Age set to {age}")Virtual Environments
Why Virtual Environments?
Virtual environments isolate project dependencies to avoid conflicts between projects.
Creating and Using venv
# Create virtual environment
python3 -m venv venv
# Activate (macOS/Linux)
source venv/bin/activate
# Activate (Windows)
venv\Scripts\activate
# Install packages
pip install requests
# List installed packages
pip list
# Save dependencies
pip freeze > requirements.txt
# Install from requirements
pip install -r requirements.txt
# Deactivate
deactivateProject Structure
my-project/
├── venv/ # Virtual environment (don't commit)
├── src/ # Source code
│ └── main.py
├── tests/ # Test files
├── requirements.txt # Dependencies
└── .gitignore # Ignore venv/Best Practices
Code Style
✅ Use snake_case for variables and functions
✅ Use PascalCase for classes
✅ Use UPPERCASE for constants
✅ Add type hints for function parameters and return types
✅ Write docstrings for functions
# Good
def calculate_total_price(items: list[float]) -> float:
"""Calculate the total price of items."""
return sum(items)
# Bad
def CalculatePrice(x): # Wrong naming, no types
return sum(x)Common Pitfalls
❌ Mutable default arguments:
# BAD - list is shared across calls!
def add_item(item: str, items: list[str] = []) -> list[str]:
items.append(item)
return items
# GOOD
def add_item(item: str, items: list[str] | None = None) -> list[str]:
if items is None:
items = []
items.append(item)
return items❌ Modifying list while iterating:
# BAD
numbers = [1, 2, 3, 4, 5]
for num in numbers:
if num % 2 == 0:
numbers.remove(num) # Causes skipping!
# GOOD
numbers = [num for num in numbers if num % 2 != 0]Practice Exercises
Exercise 1: Temperature Converter
def celsius_to_fahrenheit(celsius: float) -> float:
"""Convert Celsius to Fahrenheit."""
return (celsius * 9/5) + 32
def fahrenheit_to_celsius(fahrenheit: float) -> float:
"""Convert Fahrenheit to Celsius."""
return (fahrenheit - 32) * 5/9Exercise 2: Word Counter
def count_words(text: str) -> dict[str, int]:
"""Count word frequencies in text."""
words = text.lower().split()
word_counts: dict[str, int] = {}
for word in words:
word_counts[word] = word_counts.get(word, 0) + 1
return word_counts
# Example
text = "hello world hello python world"
print(count_words(text))
# {'hello': 2, 'world': 2, 'python': 1}Exercise 3: Simple TODO List
def todo_app() -> None:
"""Simple TODO list application."""
todos: list[str] = []
while True:
print("\n1. Add task")
print("2. View tasks")
print("3. Remove task")
print("4. Quit")
choice: str = input("Choose option: ")
match choice:
case "1":
task = input("Enter task: ")
todos.append(task)
case "2":
for i, task in enumerate(todos, 1):
print(f"{i}. {task}")
case "3":
index = int(input("Task number: ")) - 1
if 0 <= index < len(todos):
todos.pop(index)
case "4":
breakSummary and Key Takeaways
✅ Python uses dynamic typing but type hints improve code quality
✅ Use f-strings for string formatting (modern and readable)
✅ Match/case is powerful for pattern matching (Python 3.10+)
✅ Lists are mutable, tuples are immutable
✅ Dictionaries map keys to values (fast lookups)
✅ Sets store unique elements (great for membership testing)
✅ Always use with statements for file operations
✅ Handle exceptions gracefully with try/except
✅ Use virtual environments for every project
✅ Follow PEP 8 style guide for readable code
Next Steps
You've completed Phase 1! You now understand Python's core syntax and can write basic programs. Ready to level up?
Continue to: Phase 2: OOP & Advanced Features →
Back to roadmap: Python Learning Roadmap →
Recommended practice: Build a CLI tool (calculator, file organizer, or password generator) to reinforce these fundamentals before moving on!
📬 Subscribe to Newsletter
Get the latest blog posts delivered to your inbox every week. No spam, unsubscribe anytime.
We respect your privacy. Unsubscribe at any time.
💬 Comments
Sign in to leave a comment
We'll never post without your permission.