Toolmingo
Guides17 min read

Python Tutorial for Beginners (2025): Learn Python Step by Step

Complete Python tutorial for absolute beginners. Learn Python syntax, data types, functions, OOP, and build real projects. Free guide with code examples.

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:

  1. Go to python.org/downloads
  2. Download the latest Python 3.x installer
  3. Run it — check "Add Python to PATH" before clicking Install
  4. 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, AGE are 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.

Keep reading

All Toolmingotools are free & run in your browser

No sign-up, no upload, no watermark. Your files never leave your device.

Browse all tools