If you are looking for the most practical and complete Python cheat sheet for 2025, you’ve landed in the right place. Python is one of the world’s most popular programming languages — loved by beginners for its simplicity and embraced by professionals for its flexibility in web development, data science, artificial intelligence, machine learning, and automation. This cheat sheet by Solviyo is designed to be your one-stop Python reference, covering everything from basic syntax and variables to advanced concepts like object-oriented programming, decorators, generators, async, and modules.

Whether you are a student learning Python for the first time, a developer brushing up for a coding interview, or a data scientist needing a quick reference for daily work, this Python quick reference guide is structured to save you time. It includes ready-to-use examples, copyable code snippets, best practices, and performance notes — all organized into clear sections. Each topic is explained in plain language with practical tips so you can quickly learn Python, revise concepts, or debug faster.

Some of the most searched topics like Python functions, loops, conditionals, data types, string methods, list comprehensions, dictionaries, sets, and classes are covered with examples and tables. Advanced users will find dedicated sections on Python decorators, dataclasses, enums, pattern matching (PEP 634), virtual environments, and dependency management. We also include insights into when to use specific data structures and the subtle differences between class methods, static methods, and instance methods.

For developers preparing for interviews, this page doubles as a Python interview preparation cheat sheet, giving you all the essential Python syntax and tricks in one place. If you prefer offline reading, you can download the Python cheat sheet PDF version for free and keep it handy on your desktop or mobile device. Bookmark this guide now — it’s your ultimate Python quick reference for 2025.

⏳ Generating your PDF, please wait...

Hello Python

Installing

Install Python from the OS package manager or python.org. Example commands:

# Install via apt (Linux)
sudo apt install python3

# macOS (Homebrew)
brew install python

# Windows (winget)
winget install Python.Python.3

# verify with
python3 --version

Running Scripts

Save code as hello.py and run it from the shell:

# hello.py
print("Hello from Solviyo!")

# Run:
python3 hello.py

REPL (Interactive Mode)

Quickly test lines of code in the REPL (use Ctrl+D to exit):

python3
>>> # type expressions and press Enter
>>> 2 + 3
5
>>> print("REPL test - Solviyo")
REPL test - Solviyo

Comments & Documentation

Inline Comments

Use # for single-line comments and short notes. Put explanatory comments where helpful.

# add two numbers
result = 5 + 3

Docstrings

Use triple-quoted strings for function/class/module documentation. Docstrings are accessible via .__doc__ or help().

def greet(name: str) -> str:
    """Return a greeting.

    Example:
        >>> greet("Solviyo")
        'Hello, Solviyo!'
    """
    return f"Hello, {name}"

Typing Annotations

Type hints clarify intent and help tooling (linters, autocomplete). They are not enforced at runtime by default.

def add(x: int, y: int) -> int:
    """Add two integers (used in Solviyo examples)."""
    return x + y

# Example
result: int = add(2, 3)
Note: Type hints improve readability and work with tools like mypy, IDEs, and language servers.

Variables & Data Types

Python variables don’t need explicit declaration — they’re created when you assign a value.

# Solviyo example variables
x = 42          # int
pi = 3.14159    # float
name = "Solviyo" # string
is_active = True # boolean
nothing = None   # special "no value"

Type Casting

Convert between types using built-in functions:

x = int("5")       # string → int
y = float(10)      # int → float
z = str(99)        # int → string
flag = bool(0)     # → False
check = bool(123)  # → True
Note: Use type() to check the data type: type(name).

Operators

Arithmetic Operators

a, b = 7, 3
print(a + b)  # 10 (addition)
print(a - b)  # 4  (subtraction)
print(a * b)  # 21 (multiplication)
print(a / b)  # 2.333... (division)
print(a // b) # 2  (floor division)
print(a % b)  # 1  (modulus)
print(a ** b) # 343 (exponentiation)

Comparison Operators

a, b = 5, 10
print(a == b)  # False
print(a != b)  # True
print(a > b)   # False
print(a < b)   # True
print(a >= 5)  # True
print(b <= 10) # True

Logical Operators

x, y = True, False
print(x and y) # False
print(x or y)  # True
print(not x)   # False

Bitwise Operators

Operate on the binary representation of integers.

a, b = 6, 3  # (110, 011 in binary)
print(a & b)  # 2  (AND)
print(a | b)  # 7  (OR)
print(a ^ b)  # 5  (XOR)
print(~a)     # -7 (NOT)
print(a << 1) # 12 (left shift)
print(a >> 1) # 3  (right shift)

Membership Operators

text = "Solviyo"
print("S" in text)   # True
print("z" not in text) # True

Identity Operators

Check if two variables point to the same object in memory.

x = [1, 2, 3]
y = x
z = [1, 2, 3]

print(x is y)      # True (same object)
print(x is z)      # False (same value, different object)
print(x is not z)  # True

Input & Output

Python provides simple but powerful ways to interact with users and display results.

Printing Output

# Basic printing
print("Hello Solviyo")

# Print multiple values (separated by space by default)
print("Pi =", 3.14159)

# Customize separator and end
print("A", "B", "C", sep="-", end="*")
# Output: A-B-C*

User Input

input() reads a line from standard input and always returns a string.

name = input("Enter your name: ")
print("Welcome,", name)

age = int(input("Enter your age: "))
print("Next year you'll be", age + 1)

Formatted Strings

Method Example Output
f-string (recommended) f"Hello {name}" Hello Solviyo
str.format() "Pi is {:.2f}".format(3.14159) Pi is 3.14
Old style "%s is %d" % ("Age", 25) Age is 25
name = "Solviyo"
score = 95
print(f"{name} scored {score}/100")

File Redirection (Shell)

You can redirect program output to a file or read input from a file in the shell:

Command Description
python3 prog.py > out.txt Redirect program output to out.txt
python3 prog.py < in.txt Use in.txt as input for the program
python3 prog.py > out.txt 2>&1 Redirect both output and errors to out.txt

Strings

Slicing

text = "Solviyo"
print(text[0])     # S (first character)
print(text[-1])    # o (last character)
print(text[0:4])   # Solv
print(text[:4])    # Solv
print(text[4:])    # iyo
print(text[::2])   # Slv (every 2nd char)

Common Methods

Method Example Output
.lower() "Solviyo".lower() solviyo
.upper() "solviyo".upper() SOLVIYO
.strip() " hi ".strip() hi
.replace() "abc".replace("a","z") zbc
.split() "a,b,c".split(",") ['a','b','c']
.join() "-".join(["a","b"]) a-b

f-Strings

name = "Solviyo"
score = 99
print(f"{name} scored {score}/100")

pi = 3.14159
print(f"Pi rounded: {pi:.2f}")

Regex Basics

Python’s re module enables pattern matching.

import re

text = "Solviyo has 2 cats and 3 dogs"
nums = re.findall(r"\d+", text)  # find all numbers
print(nums)  # ['2', '3']

if re.search(r"cats", text):
    print("Found 'cats'!")

Lists

Creation & Slicing

items = [1, 2, 3, "Solviyo", True]
print(items[0])     # 1
print(items[-1])    # True
print(items[1:4])   # [2, 3, 'Solviyo']

Common Methods

Method Example Effect
.append() nums.append(4) Adds element at end
.extend() nums.extend([5,6]) Adds multiple elements
.insert() nums.insert(1, 99) Insert at index
.remove() nums.remove(99) Remove first match
.pop() nums.pop() Remove & return last element
.sort() nums.sort() Sort in place
.reverse() nums.reverse() Reverse in place

List Comprehensions

# Squares from 0 to 9
squares = [x**2 for x in range(10)]
print(squares)

# Filter even numbers
evens = [x for x in range(10) if x % 2 == 0]
print(evens)

Tuples

Tuples are like lists, but immutable — once created, they cannot be changed. This makes them faster and safe for fixed collections.

Immutability

t = (1, 2, 3)
print(t[0])       # 1
# t[0] = 99       # ❌ Error: 'tuple' object does not support item assignment

Packing & Unpacking

# Packing
point = (10, 20)

# Unpacking
x, y = point
print(x, y)  # 10 20

# Extended unpacking
a, *b = (1, 2, 3, 4)
print(a)  # 1
print(b)  # [2, 3, 4]

Named Tuples

For better readability, use namedtuple (from collections).

from collections import namedtuple

Point = namedtuple("Point", ["x", "y"])
p = Point(10, 20)

print(p.x, p.y)      # 10 20
print(p[0], p[1])    # still works like a tuple

Sets

Sets store unique values. Order is not guaranteed, and duplicates are automatically removed.

Creation

numbers = {1, 2, 3, 3, 2}
print(numbers)  # {1, 2, 3}

empty = set()   # correct way to make empty set

Set Operations

Operation Example Result
Union {1,2} | {2,3} {1,2,3}
Intersection {1,2} & {2,3} {2}
Difference {1,2} - {2,3} {1}
Symmetric Difference {1,2} ^ {2,3} {1,3}

Frozen Sets

frozenset is an immutable set — useful as dictionary keys or when you want fixed unique values.

fs = frozenset([1, 2, 2, 3])
print(fs)        # frozenset({1, 2, 3})
# fs.add(4)      # ❌ Error: can't modify frozenset

Dictionaries

Dictionaries store data as key–value pairs. Keys must be unique and immutable (like strings, numbers, tuples), while values can be anything.

Creation

# Literal
user = {"name": "Alice", "age": 25}

# Constructor
data = dict(x=10, y=20)

print(user["name"])  # Alice

Common Methods

Method Example Result
.keys() user.keys() dict_keys(['name','age'])
.values() user.values() dict_values(['Alice',25])
.items() user.items() dict_items([('name','Alice'),('age',25)])
.get() user.get("name") Alice
.update() user.update({"age": 26}) {'name':'Alice','age':26}
.pop() user.pop("age") 25 (removes key)

Dict Comprehensions

# Square numbers into dict
squares = {x: x**2 for x in range(5)}
print(squares)  # {0:0, 1:1, 2:4, 3:9, 4:16}

Nested Dictionaries

users = {
    "alice": {"age": 25, "role": "admin"},
    "bob": {"age": 30, "role": "editor"}
}

print(users["alice"]["role"])  # admin

Data Structure Comparisons

Python gives us multiple built-in containers. Each has its strengths — choosing the right one can make your code faster and cleaner.

Structure Key Properties Performance Notes Best Use Cases
List Ordered, mutable, allows duplicates Fast append & iteration, slower lookups (O(n)) General sequences, dynamic collections
Tuple Ordered, immutable Lighter & faster than lists, hashable (usable as dict keys) Fixed data, function returns, safe read-only data
Set Unordered, unique values Fast membership checks (O(1)), no duplicates Removing duplicates, fast lookups, math-like operations
Dict Key–value mapping, keys unique Fast key lookups & updates (O(1)) Configurations, mappings, JSON-like data
👉 Rule of thumb: - Use lists when order matters. - Use tuples when data must not change. - Use sets for uniqueness or quick membership tests. - Use dictionaries for labeled, structured data.

Conditionals

Conditionals let your code make decisions. Python uses if, elif, and else blocks, indented consistently.

x = 10

if x > 0:
    print("Positive")
elif x == 0:
    print("Zero")
else:
    print("Negative")

Ternary Operator

For short decisions, Python has a one-liner form:

age = 20
status = "Adult" if age >= 18 else "Minor"
print(status)  # Adult
Tip: Don’t overuse ternary operators — they’re best when expressions are short and readable.

Loops

Loops let you repeat code. Python has two main loop types: for and while.

for loop

Iterates directly over a sequence (no need for indexes unless you want them).

fruits = ["apple", "banana", "cherry"]
for fruit in fruits:
    print(fruit)

while loop

Runs as long as a condition is True.

count = 3
while count > 0:
    print(count)
    count -= 1
# prints: 3, 2, 1

range()

The range() function is commonly used with for loops to generate numbers.

for i in range(2, 10, 2):  # start=2, stop=10, step=2
    print(i)
# Output: 2, 4, 6, 8
👉 Use for when looping over items, 👉 Use while when looping until a condition is met.

Loop Utilities

Python adds helpers that make looping cleaner and more expressive.

enumerate()

Gives both index and value when looping through a sequence.

names = ["Alice", "Bob", "Charlie"]

for idx, name in enumerate(names, start=1):
    print(idx, name)
# 1 Alice
# 2 Bob
# 3 Charlie

zip()

Combines multiple sequences element by element.

scores = [90, 85, 78]
for name, score in zip(names, scores):
    print(f"{name}: {score}")
# Alice: 90
# Bob: 85
# Charlie: 78

any() and all()

Check conditions across sequences.

nums = [2, 4, 6, 8]

print(any(n % 2 != 0 for n in nums))  # False
print(all(n % 2 == 0 for n in nums))  # True

Loop Control

Special keywords change how loops behave.

for i in range(5):
    if i == 2:
        continue   # skip iteration
    if i == 4:
        break      # exit loop
    print(i)
else:
    print("Loop finished without break")
Keyword Meaning
break Exit the loop immediately
continue Skip the rest of the current iteration
else Runs only if loop wasn’t broken out of

Pattern Matching (PEP 634)

Python 3.10 introduced match/case for structural pattern matching, similar to switch statements in other languages but more powerful.

def handle_point(pt):
    match pt:
        case (0, 0):
            return "Origin"
        case (x, 0):
            return f"X-axis at {x}"
        case (0, y):
            return f"Y-axis at {y}"
        case (x, y):
            return f"Point ({x}, {y})"
        case _:
            return "Unknown"

print(handle_point((0, 0)))   # Origin
print(handle_point((5, 0)))   # X-axis at 5
👉 match/case works with numbers, strings, sequences, and even classes. 👉 Always include case _: as a fallback.

Defining Functions

Functions let you group reusable logic. Use def followed by a name, parameters, and an optional return statement.

def greet(name):
    return f"Hello, {name}!"

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

Arguments

Python functions are flexible in how they accept arguments. Here’s a quick overview:

Type Example Notes
Positional power(2, 3) Order matters
Keyword power(base=2, exp=3) Order doesn’t matter
Default def f(x=10) Value used if no argument passed
*args def f(*nums) Collects extra positional args (tuple)
**kwargs def f(**opts) Collects extra keyword args (dict)
def demo(*args, **kwargs):
    print("args:", args)
    print("kwargs:", kwargs)

demo(1, 2, 3, a=10, b=20)
# args: (1, 2, 3)
# kwargs: {'a': 10, 'b': 20}

Scope & Closures

Python resolves variable names using the LEGB rule: Local → Enclosing → Global → Built-in.

Scope Description
Local Names inside the current function
Enclosing Names in outer (non-global) functions
Global Names at the module level
Built-in Names preloaded by Python (e.g. len)

Examples

x = "global"

def outer():
    msg = "enclosing"
    def inner():
        nonlocal msg
        print(x, msg)
    inner()

outer()  # global enclosing
👉 global lets you modify a module-level variable. 👉 nonlocal lets you modify a variable in an enclosing (but not global) scope. 👉 Closures happen when an inner function remembers variables from its enclosing scope.

Anonymous Functions → Lambdas

Use lambda for short, throwaway functions. Best for one-liners where a full def would be overkill.

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

words = ["solviyo", "python", "cheatsheet"]
print(sorted(words, key=lambda w: len(w)))
# ['python', 'solviyo', 'cheatsheet']
👉 Lambdas are limited to a single expression. Use def for complex logic.

Decorators

Decorators wrap one function with another, adding extra behavior.

Decorator Usage
@staticmethod Bind method to class, no self
@classmethod Bind method to class, gets cls
@property Define getter/setter-like methods
def logger(func):
    def wrapper(*args, **kwargs):
        print(f"[Solviyo Log] Calling {func.__name__}")
        return func(*args, **kwargs)
    return wrapper

@logger
def greet(name):
    return f"Hello {name}"

print(greet("Python"))

Generators & Iterators

Generators produce items lazily using yield. Iterators expose __iter__() and __next__().

def countdown(n):
    while n > 0:
        yield n
        n -= 1

for num in countdown(3):
    print(num)
# 3 2 1
nums = [10, 20, 30]
it = iter(nums)

print(next(it))  # 10
print(next(it))  # 20
👉 Generators save memory — they yield one value at a time instead of building the whole list in memory.

Built-in Functional Tools

Python provides built-ins for applying functions across iterables.

Function Usage
map(func, iterable) Apply func to each item
filter(func, iterable) Keep items where func returns True
reduce(func, iterable) Accumulate to a single value (from functools)
zip(*iterables) Combine items element-wise
from functools import reduce

nums = [1, 2, 3, 4]
print(list(map(lambda x: x*2, nums)))     # [2, 4, 6, 8]
print(list(filter(lambda x: x%2==0, nums)))  # [2, 4]
print(reduce(lambda a,b: a+b, nums))      # 10
print(list(zip("abc", nums)))             # [('a',1),('b',2),('c',3)]

Imports

Python imports can be absolute, relative, or use aliases.

Type Example Notes
Absolute import math Most common; full path
Relative from . import utils Within packages; uses dots
Aliasing import numpy as np Shorter reference name
Selective from math import sqrt Import only what you need

Built-in Modules

Python comes batteries-included. Here are some must-know modules:

Module Use Case Example
math Mathematical functions math.sqrt(16) → 4.0
random Random numbers random.choice([1,2,3])
datetime Dates & times datetime.date.today()
os File system, env vars os.listdir(".")
sys Python runtime info sys.version
import math, random, datetime

print(math.factorial(5))         # 120
print(random.randint(1, 10))     # random int
print(datetime.date.today())     # current date

Creating Packages

A package is just a folder with an __init__.py file.

my_project/
│
├── app.py
├── utils/
│   ├── __init__.py
│   ├── math_tools.py
│   └── string_tools.py
# app.py
from utils import math_tools

print(math_tools.add(2, 3))

Virtual Environments

Keep dependencies isolated per project using venv.

python -m venv venv
source venv/bin/activate   # macOS/Linux
venv\Scripts\activate      # Windows
👉 When active, pip install installs into the venv, not globally.

Dependency Management

Two common ways to lock dependencies:

File Purpose Example
requirements.txt Pin exact versions requests==2.31.0
pyproject.toml Modern build metadata [tool.poetry.dependencies]
# Freeze dependencies
pip freeze > requirements.txt

# Install dependencies
pip install -r requirements.txt

Classes & Objects

In Python, everything is an object. Classes define blueprints for creating objects, bundling attributes (data) and methods (behavior).

Basic Syntax

class Dog:
    # class attribute
    species = "Canis familiaris"

    def __init__(self, name, age):
        # instance attributes
        self.name = name
        self.age = age

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

# create objects
fido = Dog("Fido", 3)
print(fido.bark())  # Fido says woof!

Attributes & Methods

Type Defined Example
Class Attribute Inside class, shared by all objects species
Instance Attribute Inside __init__, unique to each object self.name, self.age
Instance Method Defined with def, uses self bark()

Adding & Accessing Attributes

# add a new attribute dynamically
fido.color = "brown"
print(fido.color)  # brown

# access class attribute
print(Dog.species)  # Canis familiaris
👉 Use self to access instance data. 👉 Objects can have attributes added at runtime. 👉 Class attributes are shared unless shadowed by an instance attribute.

Inheritance

Inheritance lets a class (child) reuse and extend behavior from another class (parent).

Single Inheritance

class Animal:
    def speak(self):
        return "Some sound"

class Dog(Animal):
    def speak(self):
        return "Woof!"

dog = Dog()
print(dog.speak())  # Woof!

Multiple Inheritance

class Walker:
    def move(self):
        return "Walking"

class Swimmer:
    def move(self):
        return "Swimming"

class Amphibian(Walker, Swimmer):
    pass

frog = Amphibian()
print(frog.move())  # Walking (first base class wins)
👉 Python resolves method lookups using the MRO (Method Resolution Order). 👉 In Amphibian(Walker, Swimmer), Python searches in Walker → Swimmer → object.

Using super()

super() lets child classes call methods from their parent without naming it directly.

class Vehicle:
    def __init__(self, brand):
        self.brand = brand

class Car(Vehicle):
    def __init__(self, brand, model):
        super().__init__(brand)  # call parent __init__
        self.model = model

car = Car("Tesla", "Model S")
print(car.brand, car.model)  # Tesla Model S

Types of Inheritance

Type Description Example
Single One base class, one child class Dog(Animal)
Multiple Child inherits from multiple parents Amphibian(Walker, Swimmer)
Multilevel Child → Parent → Grandparent chain C → B → A
Hierarchical Multiple children from one parent Dog(Animal), Cat(Animal)

Polymorphism

Polymorphism allows different classes to define methods with the same name, but different behavior. This makes code more flexible and extensible.

Method Overriding

class Animal:
    def speak(self):
        return "Some sound"

class Dog(Animal):
    def speak(self):  # overrides parent method
        return "Woof!"

class Cat(Animal):
    def speak(self):  # overrides parent method
        return "Meow!"

animals = [Dog(), Cat()]
for a in animals:
    print(a.speak())  
    # Woof!
    # Meow!

Built-in Example

Python’s built-in functions also show polymorphism. The same len() works on strings, lists, tuples, and more:

print(len("Solviyo"))    # 7 (string length)
print(len([1, 2, 3]))    # 3 (list length)
print(len((10, 20)))     # 2 (tuple length)

Key Points

Concept Description Example
Overriding Child class redefines a parent method Dog.speak()
Same Interface Different objects respond to the same method a.speak() → Dog or Cat
Built-in Polymorphism Functions like len(), iter() len("abc"), len([1,2,3])
👉 Polymorphism is not limited to class hierarchies — Python’s duck typing means “if it walks like a duck and quacks like a duck, it’s a duck.” 👉 As long as objects implement the required methods, they can be used interchangeably.

Encapsulation

Encapsulation restricts direct access to an object’s data. In Python, this is done by naming conventions rather than enforced rules.

Public, Protected, Private

class Account:
    def __init__(self, user, balance):
        self.user = user          # public
        self._balance = balance   # protected (convention)
        self.__pin = "1234"       # private (name mangling)

    def get_balance(self):
        return f"{self.user}'s balance: {self._balance}"

    def __get_pin(self):  # private method
        return self.__pin

acc = Account("SolviyoUser", 500)

print(acc.user)        # accessible
print(acc._balance)    # accessible but discouraged
# print(acc.__pin)     # AttributeError
print(acc._Account__pin)  # accessible via name mangling (not recommended)

Access Levels

Level Convention Accessibility
Public variable Fully accessible anywhere
Protected _variable Accessible, but meant for internal use only
Private __variable Class-internal use (name mangled)
👉 Python relies on developer discipline for encapsulation — unlike Java or C++. 👉 Use getters/setters only when needed (validation, computed properties). 👉 @property is Python’s idiomatic way to manage controlled access.

Using @property

class User:
    def __init__(self, name):
        self._name = name

    @property
    def name(self):  # getter
        return self._name

    @name.setter
    def name(self, value):  # setter
        if not value:
            raise ValueError("Name cannot be empty")
        self._name = value

u = User("Solviyo")
print(u.name)   # Solviyo
u.name = "AI"   # valid update

Special Methods (Dunder Methods)

Special methods in Python start and end with __ (double underscores). They let you customize how objects behave with built-in functions and operators.

Example: Custom Class with Special Methods

class Book:
    def __init__(self, title, author, pages):
        self.title = title
        self.author = author
        self.pages = pages

    def __str__(self):   # human-readable
        return f"{self.title} by {self.author}"

    def __repr__(self):  # developer-friendly
        return f"Book({self.title!r}, {self.author!r}, {self.pages})"

    def __len__(self):   # works with len()
        return self.pages

    def __eq__(self, other):  # ==
        return self.title == other.title

b1 = Book("Python Tricks", "Solviyo", 250)
b2 = Book("Python Tricks", "Solviyo", 250)

print(str(b1))    # Python Tricks by Solviyo
print(repr(b1))   # Book('Python Tricks', 'Solviyo', 250)
print(len(b1))    # 250
print(b1 == b2)   # True

Common Special Methods

Method Purpose Example
__init__ Constructor, initialize attributes Book("Title", "Author", 100)
__str__ User-friendly string print(obj)
__repr__ Developer string (debugging) obj in REPL
__len__ Called by len() len(obj)
__eq__ Equality check obj1 == obj2
__add__ Overload + operator obj1 + obj2
__iter__, __next__ Make class iterable for x in obj
__enter__, __exit__ Context managers with obj:
👉 __str__ is for end users, __repr__ is for developers. 👉 If you only define __repr__, it’s often used as fallback for __str__. 👉 Special methods let your classes feel “native” in Python.

Class vs Static Methods

Besides normal instance methods, Python supports class methods and static methods. These are defined using decorators and control how methods access data.

Example

class MathUtils:
    pi = 3.14159

    def area_of_circle(self, r):  # instance method
        return self.pi * r * r

    @classmethod
    def get_pi(cls):  # class method
        return cls.pi

    @staticmethod
    def add(x, y):  # static method
        return x + y

m = MathUtils()

# Instance method (needs object)
print(m.area_of_circle(5))  # 78.53975

# Class method (works via class or object)
print(MathUtils.get_pi())   # 3.14159

# Static method (no access to class/instance data)
print(MathUtils.add(3, 4))  # 7

Comparison

Method Type Decorator First Arg Access Use Case
Instance None self Instance attributes & class attributes Object-specific behavior
Class @classmethod cls Class attributes (shared across instances) Factory methods, alternative constructors
Static @staticmethod None No direct access Utility functions logically tied to class
👉 @classmethod is great for alternative constructors (e.g., Date.from_string("2025-09-28")). 👉 @staticmethod is just a namespaced function inside the class. 👉 Regular instance methods remain the most common.

Dataclasses & Enums

Python provides dataclasses (for simpler class boilerplate) and enums (for named constants). These improve readability and reduce manual code.

Dataclasses

from dataclasses import dataclass

@dataclass
class Book:
    title: str
    author: str
    pages: int = 0

b1 = Book("Python 101", "Solviyo", 250)
print(b1)  # Book(title='Python 101', author='Solviyo', pages=250)

Frozen Dataclasses

Frozen dataclasses make instances immutable:

@dataclass(frozen=True)
class Config:
    api_key: str

cfg = Config("XYZ-123")
# cfg.api_key = "ABC"  # ❌ Error: cannot assign to field

Dataclass Benefits

Feature Normal Class Dataclass
Auto __init__ Manual Generated automatically
Auto __repr__ Manual Generated automatically
Immutability Manual @property frozen=True
👉 Use dataclasses when you need lightweight data containers. 👉 Frozen dataclasses are useful for config objects, keys, and constants.

Enums

from enum import Enum, auto

class Status(Enum):
    PENDING = auto()
    ACTIVE = auto()
    INACTIVE = auto()

print(Status.ACTIVE)       # Status.ACTIVE
print(Status.ACTIVE.name)  # ACTIVE
print(Status.ACTIVE.value) # 2

Enum Use Cases

Scenario Why Enums Help
Status Flags Avoids using raw strings ("active", "inactive")
Constants Groups related constants in one class
Readability Self-documenting & safer than magic numbers
👉 Enums are iterable, so you can loop over members with for status in Status. 👉 Use auto() for automatic numbering. 👉 Great for states, categories, or configuration flags.

Practice Python After Reading

Now that you’ve explored the Python Cheat Sheet, test your knowledge and sharpen your skills: