COURSE · 12 LESSONS · 100% FREE
🐍

Python Masterclass

From zero to hero — 12 comprehensive lessons covering everything from basic syntax to async programming, testing, and real-world APIs.

0Lessons
0Code Examples
ZeroPrerequisites
0%
You've completed 0 of 12 lessons
J/ Next
K/ Prev
Esc Collapse
/ Search
Foundations

Dynamic Typing

Python uses dynamic typing — you don't declare variable types. The interpreter infers the type at runtime.

Python
name = "Mayank"          # str
age = 15                 # int
height = 5.8             # float
is_student = True        # bool

print(type(name))        # <class 'str'>
print(type(age))         # <class 'int'>

# Type conversion
x = "42"
y = int(x)               # 42
z = float("3.14")        # 3.14
s = str(100)             # "100"

Collection Types

Python
# List — ordered, mutable
fruits = ["apple", "banana", "cherry"]
fruits.append("date")

# Tuple — ordered, immutable
colors = ("red", "green", "blue")

# Dict — key-value pairs
person = {"name": "Mayank", "age": 15}

# Set — unordered, no duplicates
unique = {1, 2, 3, 2, 1}   # {1, 2, 3}
💡
PEP 8 Naming Python uses snake_case for variables (my_variable), not camelCase. Stick to PEP 8 conventions.

String Operations

Python
# f-strings — preferred since Python 3.6
name = "World"
print(f"Hello, {name}!")       # Hello, World!

# Multi-line strings
poem = """Roses are red,
Violets are blue,
Python is awesome,
And so are you."""

# Common methods
s = "  Hello, Python!  "
print(s.strip())               # "Hello, Python!"
print(s.lower())               # "  hello, python!  "
print(s.replace("Python", "World"))
print(s.split(","))

Key Takeaways

  • Python is dynamically typed — no type declarations needed
  • Use f"{}" for string interpolation
  • Lists are mutable, tuples are immutable
  • Dicts are ordered (3.7+) and the most versatile collection
  • Sets are perfect for deduplication and fast membership testing
🧪 Quick Check
What is the output of type([])?

Conditionals

Python
score = 85

if score >= 90:
    grade = "A"
elif score >= 80:
    grade = "B"
elif score >= 70:
    grade = "C"
else:
    grade = "F"

# Ternary operator
status = "pass" if score >= 60 else "fail"

# Truthy/Falsy: None, False, 0, "", [], {}, set() are falsy
name = ""
if not name:
    print("Name is empty")

For Loops

Python
languages = ["Python", "Go", "Rust"]
for lang in languages:
    print(lang)

# range()
for i in range(5):          # 0, 1, 2, 3, 4
    print(i)

# Enumerate — index + value
for idx, lang in enumerate(languages):
    print(f"{idx}: {lang}")

# Dict iteration
user = {"name": "Mayank", "age": 15}
for key, value in user.items():
    print(f"{key} = {value}")

While Loops

Python
count = 0
while count < 5:
    print(count)
    count += 1

# while True + break
while True:
    user_input = input("Enter 'quit' to exit: ")
    if user_input == "quit":
        break

# continue — skip even numbers
for i in range(10):
    if i % 2 == 0:
        continue
    print(i)              # 1, 3, 5, 7, 9
Pythonic Iteration Python's for loop is a "for each" iterator — no C-style index needed. Use enumerate() when you need the index.
🧪 Quick Check
What does range(2, 10, 2) produce?
← PrevVariables & Data Types

Function Basics

Python
def greet(name):
    """Greet a person by name."""
    return f"Hello, {name}!"

print(greet("Mayank"))    # Hello, Mayank!

# Default parameters
def power(base, exp=2):
    return base ** exp

print(power(3))           # 9
print(power(3, 3))        # 27

# Multiple return values
def stats(numbers):
    return min(numbers), max(numbers), sum(numbers) / len(numbers)

lo, hi, avg = stats([10, 20, 30, 40, 50])

Args & Kwargs

Python
def add_all(*args):
    return sum(args)

print(add_all(1, 2, 3, 4))    # 10

def build_profile(**kwargs):
    return kwargs

profile = build_profile(name="Mayank", age=15, city="Nagpur")

# Combining both
def func(required, *args, **kwargs):
    print(f"Required: {required}")
    print(f"Args: {args}")
    print(f"Kwargs: {kwargs}")

Lambda & Higher-Order Functions

Python
square = lambda x: x ** 2
print(square(5))   # 25

numbers = [3, 1, 4, 1, 5, 9]
sorted_nums = sorted(numbers, key=lambda x: -x)

doubled = list(map(lambda x: x * 2, [1, 2, 3]))
evens = list(filter(lambda x: x % 2 == 0, range(10)))

Decorators

Python
import time

def timer(func):
    def wrapper(*args, **kwargs):
        start = time.time()
        result = func(*args, **kwargs)
        print(f"{func.__name__} took {time.time()-start:.4f}s")
        return result
    return wrapper

@timer
def slow_function():
    time.sleep(1)
    return "done"
💡
Decorator TipUse @functools.wraps to preserve the original function's metadata when writing decorators.
← PrevControl Flow

Slicing & Unpacking

Python
nums = [3, 1, 4, 1, 5, 9, 2, 6]
print(nums[1:5])      # [1, 4, 1, 5]
print(nums[::2])      # [3, 4, 5, 2]
print(nums[::-1])     # reversed

first, *middle, last = [1, 2, 3, 4, 5]
# first=1, middle=[2,3,4], last=5

Comprehensions

Python
# List comprehension
squares = [x**2 for x in range(10)]
evens = [x for x in range(20) if x % 2 == 0]

# Flatten nested list
matrix = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
flat = [n for row in matrix for n in row]

# Dict comprehension
names = ["Mayank", "Aisha", "Dev"]
name_lengths = {name: len(name) for name in names}

# Set comprehension
text = "hello world"
unique_chars = {c for c in text if c != ' '}

Generators

Python
# Generator — lazy evaluation, memory efficient
gen = (x**2 for x in range(1000000))
print(next(gen))   # 0

def fibonacci():
    a, b = 0, 1
    while True:
        yield a
        a, b = b, a + b

fib = fibonacci()
first_10 = [next(fib) for _ in range(10)]
# [0, 1, 1, 2, 3, 5, 8, 13, 21, 34]
PerformanceComprehensions are often faster than for loops because iteration happens in C rather than Python bytecode.
← PrevFunctions

Basic File Operations

Python
# Write (creates or overwrites)
with open("output.txt", "w") as f:
    f.write("Hello, World!\n")

# Append
with open("output.txt", "a") as f:
    f.write("Line two\n")

# Read line by line (memory efficient)
with open("output.txt", "r") as f:
    for line in f:
        print(line.strip())

JSON & CSV

Python
import json, csv

data = {"name": "Mayank", "age": 15, "langs": ["Python", "Go"]}

# JSON
with open("data.json", "w") as f:
    json.dump(data, f, indent=2)
with open("data.json", "r") as f:
    loaded = json.load(f)

# CSV
with open("data.csv", "w", newline="") as f:
    writer = csv.writer(f)
    writer.writerow(["Name", "Age"])
    writer.writerow(["Mayank", 15])

pathlib (Modern)

Python
from pathlib import Path

p = Path("data") / "output" / "result.txt"
p.write_text("Hello from pathlib!")
content = p.read_text()

py_files = list(Path(".").glob("**/*.py"))
print(p.suffix)     # ".txt"
print(p.stem)       # "result"
⚠️
Always use withNever use f = open(...) without with — it guarantees the file is closed even if exceptions occur.
← PrevLists & Comprehensions
Intermediate

Basic try/except

Python
try:
    result = 10 / 0
except ZeroDivisionError:
    print("Cannot divide by zero!")

# Multiple exceptions
try:
    x = int(input("Enter a number: "))
    result = 100 / x
except ValueError:
    print("Not a valid number!")
except ZeroDivisionError:
    print("Cannot divide by zero!")
except (ValueError, TypeError) as e:
    print(f"Error: {e}")

try/except/else/finally

Python
try:
    file = open("data.txt", "r")
    content = file.read()
except FileNotFoundError:
    print("File not found!")
else:
    print(f"Read {len(content)} characters")
finally:
    print("Always runs — cleanup here")

Custom Exceptions

Python
class InsufficientFundsError(Exception):
    def __init__(self, balance, amount):
        self.balance = balance
        self.amount = amount
        super().__init__(f"Cannot withdraw ${amount}. Balance: ${balance}")

class BankAccount:
    def __init__(self, balance=0):
        self.balance = balance

    def withdraw(self, amount):
        if amount > self.balance:
            raise InsufficientFundsError(self.balance, amount)
        self.balance -= amount

account = BankAccount(100)
try:
    account.withdraw(150)
except InsufficientFundsError as e:
    print(e)   # Cannot withdraw $150. Balance: $100
🚫
Never use bare except:It catches everything including KeyboardInterrupt and SystemExit. Always catch specific exceptions.
← PrevFile I/O

Class Basics

Python
class Dog:
    species = "Canis familiaris"

    def __init__(self, name, age):
        self.name = name
        self.age = age

    def bark(self):
        return f"{self.name} says Woof!"

    def __repr__(self):
        return f"Dog('{self.name}', {self.age})"

buddy = Dog("Buddy", 3)
print(buddy.bark())

Inheritance & Polymorphism

Python
class Animal:
    def __init__(self, name):
        self.name = name
    def speak(self):
        raise NotImplementedError

class Cat(Animal):
    def speak(self):
        return f"{self.name} says Meow!"

class Dog(Animal):
    def speak(self):
        return f"{self.name} says Woof!"

animals = [Cat("Whiskers"), Dog("Rex")]
for animal in animals:
    print(animal.speak())

Properties & Dunder Methods

Python
class Vector:
    def __init__(self, x, y):
        self.x, self.y = x, y
    def __add__(self, other):
        return Vector(self.x + other.x, self.y + other.y)
    def __mul__(self, scalar):
        return Vector(self.x * scalar, self.y * scalar)
    def __repr__(self):
        return f"Vector({self.x}, {self.y})"
    def __eq__(self, other):
        return self.x == other.x and self.y == other.y

v1 = Vector(1, 2)
v2 = Vector(3, 4)
print(v1 + v2)      # Vector(4, 6)
← PrevError Handling

Imports

Python
import math
from math import pi, sqrt
import numpy as np

# __name__ guard
if __name__ == "__main__":
    main()

Virtual Environments

Shell
python -m venv venv
venv\Scripts\activate          # Windows
source venv/bin/activate       # macOS/Linux

pip install requests flask
pip freeze > requirements.txt
pip install -r requirements.txt
deactivate
← PrevOOP
Advanced

GET Requests

Python
import requests

response = requests.get("https://api.github.com/users/mayank-dev-15")
print(response.status_code)    # 200
print(response.json())

# Query parameters
params = {"q": "python", "sort": "stars", "per_page": 5}
response = requests.get("https://api.github.com/search/repositories", params=params)

POST, PUT, DELETE

Python
# POST
payload = {"title": "Hello", "body": "World", "userId": 1}
response = requests.post(
    "https://jsonplaceholder.typicode.com/posts",
    json=payload
)

# PUT
response = requests.put(
    "https://jsonplaceholder.typicode.com/posts/1",
    json={"title": "Updated"}
)

# DELETE
response = requests.delete("https://jsonplaceholder.typicode.com/posts/1")

Error Handling

Python
try:
    response = requests.get(url, timeout=5)
    response.raise_for_status()
    data = response.json()
except requests.exceptions.Timeout:
    print("Request timed out")
except requests.exceptions.HTTPError as e:
    print(f"HTTP error: {e.response.status_code}")
except requests.exceptions.ConnectionError:
    print("Failed to connect")
Rate LimitingGitHub's API: 60 req/hour unauthenticated. Add an Authorization header with a PAT for 5000/hour.
← PrevModules & Packages

Stack & Queue

Python
from collections import deque

# Stack (LIFO)
stack = deque()
stack.append("page1")
stack.append("page2")
current = stack.pop()    # "page2"

# Queue (FIFO)
queue = deque()
queue.append("user1")
queue.append("user2")
next_user = queue.popleft()  # "user1"

defaultdict & Counter

Python
from collections import defaultdict, Counter

word_count = defaultdict(int)
for word in "hello world hello".split():
    word_count[word] += 1
# {'hello': 2, 'world': 1}

counts = Counter(["a", "b", "a", "c", "a"])
print(counts.most_common(2))   # [('a', 3), ('b', 1)]

Binary Tree

Python
class TreeNode:
    def __init__(self, val=0, left=None, right=None):
        self.val, self.left, self.right = val, left, right

def insert(root, val):
    if not root: return TreeNode(val)
    if val < root.val:
        root.left = insert(root.left, val)
    else:
        root.right = insert(root.right, val)
    return root

def inorder(root):
    if root:
        yield from inorder(root.left)
        yield root.val
        yield from inorder(root.right)

root = None
for val in [5, 3, 7, 1, 4]:
    root = insert(root, val)
print(list(inorder(root)))  # [1, 3, 4, 5, 7]
← PrevWorking with APIs

Coroutines & asyncio

Python
import asyncio

async def greet(name, delay):
    await asyncio.sleep(delay)
    print(f"Hello, {name}!")

async def main():
    # Sequential — 3s total
    await greet("Mayank", 1)
    await greet("Python", 2)

    # Concurrent — ~2s total
    await asyncio.gather(
        greet("Mayank", 1),
        greet("Python", 2)
    )

asyncio.run(main())

Async HTTP

Python
import asyncio, aiohttp

async def fetch(session, url):
    async with session.get(url) as resp:
        return await resp.json()

async def main():
    urls = [
        "https://api.github.com/users/mayank-dev-15",
        "https://api.github.com/users/torvalds"
    ]
    async with aiohttp.ClientSession() as session:
        tasks = [fetch(session, url) for url in urls]
        results = await asyncio.gather(*tasks)
        for r in results:
            print(f"{r['login']}: {r['public_repos']} repos")

asyncio.run(main())
💡
Async ≠ ParallelismAsync is for I/O-bound work (network, files). For CPU-bound work, use multiprocessing.
← PrevData Structures

pytest Basics

Python
import pytest

def add(a, b):
    return a + b

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

def test_add_negative():
    assert add(-1, -1) == -2

# Fixtures
@pytest.fixture
def sample_data():
    return {"users": ["Mayank", "Aisha"], "count": 2}

def test_sample(sample_data):
    assert sample_data["count"] == len(sample_data["users"])

# Parameterized
@pytest.mark.parametrize("a,b,expected", [
    (1, 2, 3), (0, 0, 0), (-1, 1, 0),
])
def test_add_param(a, b, expected):
    assert add(a, b) == expected

Mocking

Python
from unittest.mock import Mock, patch
import requests

def get_user(user_id):
    return requests.get(f"https://api.github.com/users/{user_id}").json()

def test_get_user():
    with patch("requests.get") as mock_get:
        mock_get.return_value.json.return_value = {
            "login": "mayank-dev-15",
            "public_repos": 10
        }
        result = get_user("mayank-dev-15")
        assert result["login"] == "mayank-dev-15"
        mock_get.assert_called_once()
← PrevAsync Programming

📚 Resources & Further Learning

📖
Official Python Docs
The definitive reference for the Python language and standard library.
docs.python.org →
📘
Automate the Boring Stuff
Free online book — practical Python projects for beginners.
automatetheboringstuff.com →
🎯
Real Python
High-quality tutorials, articles, and courses on all things Python.
realpython.com →
🧪
pytest Docs
The pytest testing framework — fixtures, plugins, and best practices.
docs.pytest.org →
asyncio Docs
Official asyncio library — coroutines, tasks, and event loops.
docs.python.org →
📦
PyPI
The Python Package Index — 500,000+ packages for every use case.
pypi.org →
AI
Python Tutor
ZenMux · GLM 4.7 Flash
Ask me anything about Python! I can help with code examples, debugging, best practices, or explain any concept from the lessons above.