Python is the world's most popular programming language — used in web development, data science, AI, automation, and more. This tutorial takes you from zero to writing real Python programs, with no prior programming experience required.
What you'll learn
| Topic | What you'll be able to do |
|---|---|
| Setup | Install Python and write your first program |
| Syntax & variables | Understand how Python code works |
| Data types | Work with strings, numbers, lists, dicts |
| Control flow | Use if/else, loops, and conditions |
| Functions | Write reusable, clean code |
| File I/O | Read and write files |
| OOP | Build classes and objects |
| Modules | Use Python's standard library |
| Projects | Build 3 real programs |
Python version used: Python 3.12+ (latest stable as of 2025)
Part 1 — Why Python?
Python beats every other language for beginners for five reasons:
1. Readable syntax — reads like English
2. No semicolons, no curly braces, no type declarations
3. Huge standard library (batteries included)
4. Massive ecosystem (350k+ packages on PyPI)
5. Runs on Windows, Mac, Linux, anywhere
| Use case | Example tools |
|---|---|
| Web development | Django, FastAPI, Flask |
| Data science | NumPy, Pandas, Matplotlib |
| Machine learning | PyTorch, TensorFlow, scikit-learn |
| Automation & scripting | Selenium, Playwright, subprocess |
| DevOps | Ansible, Fabric, boto3 (AWS) |
| APIs | requests, httpx, aiohttp |
| CLI tools | argparse, Click, Typer |
| Games | Pygame |
Part 2 — Setup
2.1 Install Python
Windows:
- Go to python.org/downloads
- Download the latest Python 3.x installer
- Run it — check "Add Python to PATH" before clicking Install
- Open Command Prompt → type
python --version
Mac:
# Option 1: official installer (python.org)
# Option 2: Homebrew (recommended for developers)
brew install python
python3 --version
Linux (Ubuntu/Debian):
sudo apt update
sudo apt install python3 python3-pip
python3 --version
2.2 Choose an editor
| Editor | Best for | Free? |
|---|---|---|
| VS Code | All-purpose, best extensions | Yes |
| PyCharm CE | Python-only, most Python features | Yes |
| Thonny | Absolute beginners | Yes |
| Jupyter Notebook | Data science, exploration | Yes |
| IDLE | Comes with Python, minimal | Yes |
Recommendation for beginners: VS Code with the Python extension.
2.3 Your first program
Create a file called hello.py:
print("Hello, World!")
Run it:
python hello.py
# Output: Hello, World!
Congratulations — you're a Python programmer.
Part 3 — Python syntax basics
3.1 Comments
# This is a single-line comment
"""
This is a
multi-line string, often used as
a docstring or block comment.
"""
3.2 Variables
Python is dynamically typed — no need to declare variable types.
name = "Alice" # str
age = 30 # int
height = 5.7 # float
is_student = True # bool
nothing = None # NoneType
Rules for variable names:
- Start with a letter or underscore (
_) - No spaces — use
snake_case(Python convention) - Case-sensitive:
age,Age,AGEare three different variables
3.3 print() and input()
# print() outputs to the terminal
print("Hello")
print("Name:", "Alice", "Age:", 30)
# input() reads from keyboard (always returns a string)
name = input("What's your name? ")
print("Hello,", name)
3.4 Python uses indentation
Python uses 4 spaces (or 1 tab) to define code blocks — no {} needed:
# CORRECT
if True:
print("This is indented")
print("So is this")
# WRONG — IndentationError
if True:
print("Missing indent")
Part 4 — Data types
4.1 Strings
greeting = "Hello, World!"
name = 'Alice' # single or double quotes, both work
multiline = """Line 1
Line 2
Line 3"""
# String methods
print(greeting.upper()) # HELLO, WORLD!
print(greeting.lower()) # hello, world!
print(greeting.replace("World", "Python")) # Hello, Python!
print(greeting.split(", ")) # ['Hello', 'World!']
print(len(greeting)) # 13
# f-strings (best way to format strings, Python 3.6+)
name = "Alice"
age = 30
print(f"My name is {name} and I'm {age} years old.")
# My name is Alice and I'm 30 years old.
# f-string expressions
print(f"2 + 2 = {2 + 2}") # 2 + 2 = 4
print(f"Pi: {3.14159:.2f}") # Pi: 3.14
4.2 Numbers
# int
x = 10
y = -3
big = 1_000_000 # underscores for readability
# float
pi = 3.14159
price = 9.99
# Arithmetic
print(10 + 3) # 13 (addition)
print(10 - 3) # 7 (subtraction)
print(10 * 3) # 30 (multiplication)
print(10 / 3) # 3.3333... (float division)
print(10 // 3) # 3 (floor division)
print(10 % 3) # 1 (modulo — remainder)
print(10 ** 3) # 1000 (exponentiation)
# Type conversion
print(int("42")) # 42
print(float("3.14")) # 3.14
print(str(100)) # "100"
4.3 Booleans
is_true = True
is_false = False
# Comparison operators
print(5 > 3) # True
print(5 == 5) # True
print(5 != 3) # True
print(5 >= 5) # True
# Logical operators
print(True and False) # False
print(True or False) # True
print(not True) # False
# Truthy and falsy values
# Falsy: False, 0, 0.0, "", [], {}, None
# Truthy: everything else
if []:
print("truthy")
else:
print("falsy") # this runs
4.4 Lists
Lists are ordered, mutable collections.
fruits = ["apple", "banana", "cherry"]
numbers = [1, 2, 3, 4, 5]
mixed = [1, "hello", True, 3.14] # mixed types allowed
# Indexing (0-based)
print(fruits[0]) # apple
print(fruits[-1]) # cherry (last item)
# Slicing [start:end:step]
print(numbers[1:4]) # [2, 3, 4]
print(numbers[:3]) # [1, 2, 3]
print(numbers[::2]) # [1, 3, 5] (every 2nd)
# Modifying
fruits.append("mango") # add to end
fruits.insert(1, "blueberry") # insert at index
fruits.remove("banana") # remove by value
popped = fruits.pop() # remove and return last
fruits.sort() # sort in place
fruits.reverse() # reverse in place
# Useful operations
print(len(fruits)) # length
print("apple" in fruits) # True (membership test)
print(fruits.count("apple")) # count occurrences
4.5 Tuples
Tuples are ordered, immutable collections.
coordinates = (10, 20)
rgb = (255, 0, 128)
single = (42,) # trailing comma needed for single-item tuple
# Access same as list
print(coordinates[0]) # 10
# Unpacking
x, y = coordinates
print(x, y) # 10 20
# Useful for multiple return values
def min_max(numbers):
return min(numbers), max(numbers)
low, high = min_max([3, 1, 4, 1, 5, 9])
print(low, high) # 1 9
4.6 Dictionaries
Dictionaries are key-value pairs.
person = {
"name": "Alice",
"age": 30,
"city": "New York"
}
# Access
print(person["name"]) # Alice
print(person.get("email", "N/A")) # N/A (safe, no KeyError)
# Modify
person["age"] = 31 # update
person["email"] = "a@b.com" # add new key
del person["city"] # delete
# Iterate
for key in person:
print(key, "->", person[key])
for key, value in person.items():
print(f"{key}: {value}")
# Useful methods
print(person.keys()) # dict_keys(['name', 'age', 'email'])
print(person.values()) # dict_values(['Alice', 31, 'a@b.com'])
print("name" in person) # True
4.7 Sets
Sets are unordered collections of unique elements.
fruits = {"apple", "banana", "cherry", "apple"}
print(fruits) # {'apple', 'banana', 'cherry'} (no duplicates)
# Operations
fruits.add("mango")
fruits.remove("banana")
print("apple" in fruits) # True
# Set operations
a = {1, 2, 3, 4}
b = {3, 4, 5, 6}
print(a | b) # union: {1, 2, 3, 4, 5, 6}
print(a & b) # intersection: {3, 4}
print(a - b) # difference: {1, 2}
print(a ^ b) # symmetric difference: {1, 2, 5, 6}
Data types quick reference
| Type | Example | Mutable? | Ordered? | Duplicates? |
|---|---|---|---|---|
str |
"hello" |
No | Yes | Yes |
int |
42 |
No | — | — |
float |
3.14 |
No | — | — |
bool |
True |
No | — | — |
list |
[1, 2, 3] |
Yes | Yes | Yes |
tuple |
(1, 2, 3) |
No | Yes | Yes |
dict |
{"a": 1} |
Yes | Yes (3.7+) | Keys: No |
set |
{1, 2, 3} |
Yes | No | No |
Part 5 — Control flow
5.1 if / elif / else
score = 85
if score >= 90:
grade = "A"
elif score >= 80:
grade = "B"
elif score >= 70:
grade = "C"
elif score >= 60:
grade = "D"
else:
grade = "F"
print(f"Score: {score}, Grade: {grade}") # Score: 85, Grade: B
One-liner (ternary):
status = "pass" if score >= 60 else "fail"
5.2 for loops
# Loop over a list
fruits = ["apple", "banana", "cherry"]
for fruit in fruits:
print(fruit)
# Loop over a range
for i in range(5): # 0, 1, 2, 3, 4
print(i)
for i in range(1, 6): # 1, 2, 3, 4, 5
print(i)
for i in range(0, 10, 2): # 0, 2, 4, 6, 8
print(i)
# Enumerate — index + value
for i, fruit in enumerate(fruits):
print(f"{i}: {fruit}")
# 0: apple
# 1: banana
# 2: cherry
# zip — two lists together
names = ["Alice", "Bob", "Charlie"]
scores = [90, 85, 92]
for name, score in zip(names, scores):
print(f"{name}: {score}")
5.3 while loops
count = 0
while count < 5:
print(count)
count += 1
# User input loop
while True:
answer = input("Type 'quit' to exit: ")
if answer == "quit":
break
print("You typed:", answer)
5.4 break, continue, pass
# break — exit the loop
for i in range(10):
if i == 5:
break
print(i) # 0, 1, 2, 3, 4
# continue — skip to next iteration
for i in range(10):
if i % 2 == 0:
continue
print(i) # 1, 3, 5, 7, 9
# pass — placeholder (do nothing)
for i in range(5):
pass # TODO: fill this in later
Part 6 — Functions
6.1 Defining functions
def greet(name):
"""Greet a person by name."""
return f"Hello, {name}!"
result = greet("Alice")
print(result) # Hello, Alice!
6.2 Parameters and arguments
# Default parameters
def greet(name, greeting="Hello"):
return f"{greeting}, {name}!"
print(greet("Alice")) # Hello, Alice!
print(greet("Bob", "Hi")) # Hi, Bob!
print(greet(name="Charlie", greeting="Hey")) # keyword args
# *args — variable positional arguments
def add(*numbers):
return sum(numbers)
print(add(1, 2, 3)) # 6
print(add(1, 2, 3, 4, 5)) # 15
# **kwargs — variable keyword arguments
def describe(**info):
for key, value in info.items():
print(f"{key}: {value}")
describe(name="Alice", age=30, city="NYC")
# name: Alice
# age: 30
# city: NYC
6.3 Return values
# Return nothing (implicitly returns None)
def say_hello():
print("Hello!")
# Return a single value
def square(n):
return n ** 2
# Return multiple values (tuple)
def min_max(numbers):
return min(numbers), max(numbers)
low, high = min_max([3, 1, 4, 1, 5])
print(low, high) # 1 5
6.4 Lambda functions
Short anonymous functions for simple operations:
# Syntax: lambda args: expression
square = lambda x: x ** 2
print(square(5)) # 25
# Common use: sorting
students = [("Alice", 90), ("Bob", 85), ("Charlie", 92)]
students.sort(key=lambda s: s[1]) # sort by score
print(students)
# [('Bob', 85), ('Alice', 90), ('Charlie', 92)]
6.5 List comprehensions
Compact way to build lists:
# Traditional
squares = []
for i in range(10):
squares.append(i ** 2)
# List comprehension
squares = [i ** 2 for i in range(10)]
print(squares) # [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
# With condition
evens = [i for i in range(20) if i % 2 == 0]
print(evens) # [0, 2, 4, 6, 8, 10, 12, 14, 16, 18]
# Dict comprehension
squares_dict = {i: i**2 for i in range(5)}
print(squares_dict) # {0: 0, 1: 1, 2: 4, 3: 9, 4: 16}
# Set comprehension
unique_lengths = {len(word) for word in ["cat", "dog", "elephant"]}
print(unique_lengths) # {3, 8}
Part 7 — Error handling
7.1 try / except
try:
number = int(input("Enter a number: "))
result = 10 / number
print("Result:", result)
except ValueError:
print("That's not a valid number!")
except ZeroDivisionError:
print("Can't divide by zero!")
except Exception as e:
print(f"Something went wrong: {e}")
else:
print("No errors!") # runs if no exception
finally:
print("Always runs.") # cleanup code
7.2 Common exceptions
| Exception | When it occurs |
|---|---|
ValueError |
Wrong value type (int("abc")) |
TypeError |
Wrong operation type ("a" + 1) |
IndexError |
List index out of range |
KeyError |
Dict key not found |
AttributeError |
Object has no attribute |
FileNotFoundError |
File doesn't exist |
ZeroDivisionError |
Division by zero |
NameError |
Variable not defined |
7.3 Raising exceptions
def divide(a, b):
if b == 0:
raise ValueError("Cannot divide by zero")
return a / b
try:
print(divide(10, 0))
except ValueError as e:
print(e) # Cannot divide by zero
Part 8 — File input/output
8.1 Reading files
# Basic read
with open("file.txt", "r") as f:
content = f.read() # entire file as string
print(content)
# Read line by line (memory-efficient for large files)
with open("file.txt", "r") as f:
for line in f:
print(line.strip()) # strip() removes newline
# Read all lines into a list
with open("file.txt", "r") as f:
lines = f.readlines() # ['line1\n', 'line2\n', ...]
8.2 Writing files
# Write (creates file or overwrites)
with open("output.txt", "w") as f:
f.write("Hello, file!\n")
f.write("Second line\n")
# Append
with open("output.txt", "a") as f:
f.write("New line appended\n")
8.3 Working with JSON
import json
# Python dict → JSON string
data = {"name": "Alice", "age": 30, "hobbies": ["coding", "reading"]}
json_string = json.dumps(data, indent=2)
print(json_string)
# JSON string → Python dict
parsed = json.loads(json_string)
print(parsed["name"]) # Alice
# Write dict to JSON file
with open("data.json", "w") as f:
json.dump(data, f, indent=2)
# Read JSON file into dict
with open("data.json", "r") as f:
loaded = json.load(f)
print(loaded["hobbies"]) # ['coding', 'reading']
Part 9 — Object-oriented programming
9.1 Classes and objects
class Dog:
# Class variable (shared by all instances)
species = "Canis familiaris"
# Constructor (called when creating an object)
def __init__(self, name, age):
self.name = name # instance variable
self.age = age # instance variable
# Instance method
def bark(self):
return f"{self.name} says: Woof!"
def birthday(self):
self.age += 1
# String representation
def __str__(self):
return f"Dog(name={self.name}, age={self.age})"
# Create objects (instances)
rex = Dog("Rex", 3)
buddy = Dog("Buddy", 5)
print(rex.bark()) # Rex says: Woof!
print(buddy.name) # Buddy
print(rex.species) # Canis familiaris
rex.birthday()
print(rex) # Dog(name=Rex, age=4)
9.2 Inheritance
class Animal:
def __init__(self, name):
self.name = name
def speak(self):
raise NotImplementedError("Subclass must implement speak()")
def __str__(self):
return f"{self.__class__.__name__}({self.name})"
class Dog(Animal):
def speak(self):
return f"{self.name} says: Woof!"
class Cat(Animal):
def speak(self):
return f"{self.name} says: Meow!"
animals = [Dog("Rex"), Cat("Whiskers"), Dog("Buddy")]
for animal in animals:
print(animal.speak())
# Rex says: Woof!
# Whiskers says: Meow!
# Buddy says: Woof!
9.3 Dataclasses (Python 3.7+)
For simple data-holding classes, use @dataclass:
from dataclasses import dataclass, field
@dataclass
class Point:
x: float
y: float
z: float = 0.0 # default value
def distance_to_origin(self):
return (self.x**2 + self.y**2 + self.z**2) ** 0.5
p = Point(3, 4)
print(p) # Point(x=3, y=4, z=0.0)
print(p.distance_to_origin()) # 5.0
Part 10 — Modules and packages
10.1 Importing modules
# Import entire module
import math
print(math.pi) # 3.141592653589793
print(math.sqrt(16)) # 4.0
# Import specific functions
from math import sqrt, pi
print(sqrt(25)) # 5.0
# Import with alias
import numpy as np # common convention
10.2 Useful standard library modules
| Module | Purpose | Example |
|---|---|---|
math |
Math functions | math.sqrt(16) |
random |
Random numbers | random.randint(1, 10) |
datetime |
Date/time | datetime.date.today() |
os |
OS operations | os.listdir(".") |
sys |
System functions | sys.argv |
re |
Regular expressions | re.findall(r"\d+", text) |
json |
JSON parsing | json.loads(text) |
csv |
CSV files | csv.reader(file) |
pathlib |
File paths | Path("data/file.txt") |
collections |
Extra data types | Counter, defaultdict |
itertools |
Iterators | itertools.chain(a, b) |
functools |
Functional tools | functools.lru_cache |
10.3 Installing packages with pip
# Install a package
pip install requests
# Install specific version
pip install requests==2.31.0
# Install from requirements.txt
pip install -r requirements.txt
# List installed packages
pip list
# Uninstall
pip uninstall requests
10.4 Virtual environments
Always use a virtual environment to isolate project dependencies:
# Create virtual environment
python -m venv venv
# Activate (Windows)
venv\Scripts\activate
# Activate (Mac/Linux)
source venv/bin/activate
# Deactivate
deactivate
# Save dependencies
pip freeze > requirements.txt
Part 11 — Three beginner projects
Project 1: Number guessing game
import random
def number_guessing_game():
"""Classic number guessing game."""
secret = random.randint(1, 100)
attempts = 0
max_attempts = 10
print("I'm thinking of a number between 1 and 100.")
print(f"You have {max_attempts} attempts.")
while attempts < max_attempts:
try:
guess = int(input(f"Attempt {attempts + 1}: "))
except ValueError:
print("Please enter a valid number.")
continue
attempts += 1
if guess < secret:
print("Too low!")
elif guess > secret:
print("Too high!")
else:
print(f"Correct! You got it in {attempts} attempts.")
return
print(f"Game over! The number was {secret}.")
number_guessing_game()
Project 2: To-do list app
import json
import os
TASKS_FILE = "tasks.json"
def load_tasks():
if os.path.exists(TASKS_FILE):
with open(TASKS_FILE, "r") as f:
return json.load(f)
return []
def save_tasks(tasks):
with open(TASKS_FILE, "w") as f:
json.dump(tasks, f, indent=2)
def show_tasks(tasks):
if not tasks:
print("No tasks yet.")
return
for i, task in enumerate(tasks, 1):
status = "✓" if task["done"] else "○"
print(f"{i}. [{status}] {task['title']}")
def main():
tasks = load_tasks()
while True:
print("\n=== To-Do List ===")
show_tasks(tasks)
print("\n1. Add task 2. Complete task 3. Delete task 4. Quit")
choice = input("Choice: ").strip()
if choice == "1":
title = input("Task title: ").strip()
if title:
tasks.append({"title": title, "done": False})
save_tasks(tasks)
print("Task added!")
elif choice == "2":
try:
n = int(input("Task number: ")) - 1
tasks[n]["done"] = True
save_tasks(tasks)
print("Marked as done!")
except (ValueError, IndexError):
print("Invalid number.")
elif choice == "3":
try:
n = int(input("Task number: ")) - 1
removed = tasks.pop(n)
save_tasks(tasks)
print(f"Deleted: {removed['title']}")
except (ValueError, IndexError):
print("Invalid number.")
elif choice == "4":
print("Goodbye!")
break
main()
Project 3: Weather CLI (using requests)
# pip install requests
import requests
import sys
def get_weather(city: str, api_key: str) -> None:
"""Fetch and display weather for a city."""
url = "https://api.openweathermap.org/data/2.5/weather"
params = {
"q": city,
"appid": api_key,
"units": "metric"
}
try:
response = requests.get(url, params=params, timeout=5)
response.raise_for_status()
except requests.exceptions.HTTPError as e:
if response.status_code == 404:
print(f"City '{city}' not found.")
else:
print(f"HTTP error: {e}")
return
except requests.exceptions.RequestException as e:
print(f"Network error: {e}")
return
data = response.json()
weather = data["weather"][0]["description"].capitalize()
temp = data["main"]["temp"]
feels_like = data["main"]["feels_like"]
humidity = data["main"]["humidity"]
wind = data["wind"]["speed"]
print(f"\n📍 {data['name']}, {data['sys']['country']}")
print(f" {weather}")
print(f" Temperature: {temp}°C (feels like {feels_like}°C)")
print(f" Humidity: {humidity}%")
print(f" Wind: {wind} m/s")
if __name__ == "__main__":
API_KEY = "your_openweathermap_api_key" # get free at openweathermap.org
city = " ".join(sys.argv[1:]) if len(sys.argv) > 1 else input("City: ")
get_weather(city, API_KEY)
Part 12 — Next steps
What to learn next
| Topic | Why | What to use |
|---|---|---|
| Virtual environments | Isolate dependencies | venv, uv |
| Type hints | Better code quality | int, str, list[str] |
| Testing | Catch bugs early | pytest |
| Async programming | Handle many tasks at once | asyncio, aiohttp |
| Web frameworks | Build web apps and APIs | Django, FastAPI, Flask |
| Data science | Analyze data | NumPy, Pandas, Matplotlib |
| Database access | Store data | sqlite3, SQLAlchemy |
| Packaging | Share your code | pyproject.toml, Poetry |
Recommended learning path
Week 1–2: Syntax, data types, control flow (Parts 1–5)
Week 3: Functions, comprehensions (Part 6)
Week 4: Error handling, file I/O (Parts 7–8)
Week 5–6: OOP, modules (Parts 9–10)
Week 7–8: Build the 3 projects (Part 11)
Month 2–3: Pick a specialisation (web / data / automation)
Common mistakes to avoid
| Mistake | Problem | Fix |
|---|---|---|
| Mutable default argument | def f(lst=[]) shares state across calls |
Use None, set inside: if lst is None: lst = [] |
Using == for None |
Works but not idiomatic | Use is None |
Catching bare except |
Catches SystemExit, KeyboardInterrupt | Catch Exception or specific types |
Forgetting self in methods |
NameError inside class |
Always add self as first parameter |
| Modifying list while iterating | Skips items or crashes | Iterate over a copy: for item in lst[:] |
| Integer division surprise | 3/2 is 1.5, not 1 |
Use // for floor division |
Confusing = and == |
= assigns, == compares |
Double-check in if conditions |
Not using with for files |
File stays open on error | Always use with open(...) |
Python vs other languages
| Feature | Python | JavaScript | Java | C++ |
|---|---|---|---|---|
| Syntax | Simple, readable | C-like, flexible | Verbose | Complex |
| Typing | Dynamic | Dynamic | Static | Static |
| Speed | Slow (interpreted) | Fast (V8 JIT) | Fast (JVM) | Very fast (compiled) |
| Learning curve | Gentle | Medium | Steep | Very steep |
| Best for | All-purpose, data/AI | Web, frontend | Enterprise | Systems, games |
| Package count | 350k+ (PyPI) | 2M+ (npm) | 300k+ (Maven) | Varies |
FAQ
Q: Do I need to know math to learn Python? Basic math (addition, percentages, logic) is enough to start. Data science and ML use more math later, but web dev and automation require very little.
Q: Python 2 or Python 3? Python 3, always. Python 2 reached end-of-life in 2020 and is no longer supported.
Q: Is Python good for mobile apps? Not great. Python runs on mobile via Kivy or BeeWare, but performance is poor. For mobile, choose Swift (iOS) or Kotlin (Android), or React Native/Flutter for cross-platform.
Q: How long does it take to learn Python? You can write useful programs after 2–4 weeks of daily practice (~1 hour/day). Job-ready Python (with a specialisation) typically takes 3–6 months.
Q: Should I use Python 3.12+ features?
Yes, if your environment supports them. Python 3.12 has faster startup, better error messages, and @override decorator. There's no reason to target older versions unless required.
Q: What's the difference between a list and a tuple? Lists are mutable (you can change items after creation). Tuples are immutable (fixed after creation). Use tuples for data that shouldn't change (coordinates, RGB values, function return values). Use lists when you need to add/remove items.