From zero to hero — 12 comprehensive lessons covering everything from basic syntax to async programming, testing, and real-world APIs.
Python uses dynamic typing — you don't declare variable types. The interpreter infers the type at runtime.
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"
# 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}
snake_case for variables (my_variable), not camelCase. Stick to PEP 8 conventions.
# 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(","))
f"{}" for string interpolationtype([])?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")
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}")
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
for loop is a "for each" iterator — no C-style index needed. Use enumerate() when you need the index.
range(2, 10, 2) produce?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])
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}")
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)))
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"
@functools.wraps to preserve the original function's metadata when writing decorators.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
# 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 != ' '}
# 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]
for loops because iteration happens in C rather than Python bytecode.# 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())
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])
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"
withNever use f = open(...) without with — it guarantees the file is closed even if exceptions occur.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:
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")
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
except:It catches everything including KeyboardInterrupt and SystemExit. Always catch specific exceptions.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())
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())
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)
import math
from math import pi, sqrt
import numpy as np
# __name__ guard
if __name__ == "__main__":
main()
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
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
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")
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")
Authorization header with a PAT for 5000/hour.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"
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)]
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]
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())
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())
multiprocessing.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
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()