Python Cheatsheet

Classes and OOP

Use this Python reference while you build software engineering projects, review code for technical interview prep, or polish examples for a software engineer resume.

Defining a Class

class Dog:
    # Class variable — shared by all instances
    species = "Canis lupus familiaris"

    # Constructor
    def __init__(self, name: str, age: int):
        self.name = name      # instance variable
        self.age = age

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

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

    def __str__(self):
        return f"{self.name} ({self.age} years)"

# Usage
dog = Dog("Rex", 3)
dog.name          # "Rex"
dog.bark()        # "Rex says woof!"
str(dog)          # "Rex (3 years)"
repr(dog)         # "Dog(name='Rex', age=3)"
Dog.species       # "Canis lupus familiaris"

Inheritance

class Animal:
    def __init__(self, name):
        self.name = name

    def speak(self):
        raise NotImplementedError

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

class Cat(Animal):
    def speak(self):
        return "Meow!"

# super()
class Puppy(Dog):
    def __init__(self, name, toy):
        super().__init__(name)        # call parent __init__
        self.toy = toy

    def speak(self):
        return super().speak() + " (puppy)"

# Multiple inheritance
class A:
    def method(self): return "A"

class B(A):
    def method(self): return "B"

class C(A):
    def method(self): return "C"

class D(B, C):   # MRO: D → B → C → A
    pass

D().method()     # "B"  (follows MRO)
D.__mro__        # (<class 'D'>, <class 'B'>, <class 'C'>, <class 'A'>, <class 'object'>)

Class Methods, Static Methods, Properties

class Circle:
    PI = 3.14159

    def __init__(self, radius):
        self._radius = radius

    # Instance method — first arg is the instance
    def area(self):
        return self.PI * self._radius ** 2

    # Class method — first arg is the class
    @classmethod
    def from_diameter(cls, diameter):
        return cls(diameter / 2)       # alternative constructor

    # Static method — no implicit first argument
    @staticmethod
    def is_valid_radius(r):
        return r > 0

    # Property — computed attribute with getter/setter/deleter
    @property
    def radius(self):
        return self._radius

    @radius.setter
    def radius(self, value):
        if value < 0:
            raise ValueError("radius cannot be negative")
        self._radius = value

    @radius.deleter
    def radius(self):
        del self._radius

# Usage
c = Circle(5)
c.area()                      # 78.53...
c.radius                      # 5  (calls getter)
c.radius = 10                 # calls setter
del c.radius                  # calls deleter

Circle.from_diameter(10)      # Circle(5.0)
Circle.is_valid_radius(-1)    # False

Special (Dunder) Methods

Object Lifecycle

MethodCalled when
__new__(cls, ...)Creating the instance (before __init__)
__init__(self, ...)Initializing the instance
__del__(self)Object is garbage collected

String Representation

MethodCalled when
__repr__(self)repr(obj), fallback for str()
__str__(self)str(obj), print(obj)
__format__(self, spec)format(obj, spec), f"{obj:spec}"
__bytes__(self)bytes(obj)

Comparison

MethodOperator
__eq__(self, other)==
__ne__(self, other)!= (auto-derived from __eq__)
__lt__(self, other)<
__le__(self, other)<=
__gt__(self, other)>
__ge__(self, other)>=
__hash__(self)hash(obj), dict/set key

If you define __eq__, Python sets __hash__ to None (unhashable) unless you also define it.

Arithmetic

MethodOperatorReflected
__add__(self, other)+__radd__
__sub__(self, other)-__rsub__
__mul__(self, other)*__rmul__
__truediv__(self, other)/__rtruediv__
__floordiv__(self, other)//__rfloordiv__
__mod__(self, other)%__rmod__
__pow__(self, other)**__rpow__
__neg__(self)unary -
__pos__(self)unary +
__abs__(self)abs()

In-place: __iadd__, __isub__, __imul__, etc. (+=, -=, *=).

Container / Sequence Protocol

MethodCalled when
__len__(self)len(obj)
__getitem__(self, key)obj[key]
__setitem__(self, key, val)obj[key] = val
__delitem__(self, key)del obj[key]
__contains__(self, item)item in obj
__iter__(self)iter(obj), for x in obj
__next__(self)next(obj) — implement with __iter__
__reversed__(self)reversed(obj)
__missing__(self, key)dict subclass: key not found

Context Manager

class ManagedResource:
    def __enter__(self):
        self.resource = acquire()
        return self.resource     # bound to `as` variable

    def __exit__(self, exc_type, exc_val, exc_tb):
        release(self.resource)
        return False  # True would suppress exceptions

with ManagedResource() as r:
    use(r)

Callable and Attribute Access

MethodCalled when
__call__(self, ...)obj(...) — makes instance callable
__getattr__(self, name)attribute not found normally
__getattribute__(self, name)any attribute access (use carefully)
__setattr__(self, name, val)obj.name = val
__delattr__(self, name)del obj.name
__dir__(self)dir(obj)

dataclasses

from dataclasses import dataclass, field

@dataclass
class Point:
    x: float
    y: float
    z: float = 0.0

p = Point(1.0, 2.0)
p.x                   # 1.0
repr(p)               # "Point(x=1.0, y=2.0, z=0.0)"

# Mutable defaults must use field()
@dataclass
class Config:
    tags: list[str] = field(default_factory=list)
    metadata: dict = field(default_factory=dict)

# Options
@dataclass(frozen=True)    # immutable (also hashable)
@dataclass(order=True)     # generates __lt__, __le__, etc.
@dataclass(eq=False)       # skip __eq__
@dataclass(slots=True)     # use __slots__ (Python 3.10+)

# post_init
@dataclass
class Rectangle:
    width: float
    height: float
    area: float = field(init=False)

    def __post_init__(self):
        self.area = self.width * self.height

Abstract Base Classes

from abc import ABC, abstractmethod

class Shape(ABC):
    @abstractmethod
    def area(self) -> float:
        ...

    @abstractmethod
    def perimeter(self) -> float:
        ...

    # Concrete method in abstract class is fine
    def describe(self):
        return f"Area: {self.area()}, Perimeter: {self.perimeter()}"

class Circle(Shape):
    def __init__(self, r): self.r = r
    def area(self): return 3.14159 * self.r ** 2
    def perimeter(self): return 2 * 3.14159 * self.r

# Shape()  → TypeError: Can't instantiate abstract class

__slots__

Restrict instance attributes, reduce memory, speed up attribute access.

class Point:
    __slots__ = ("x", "y")    # tuple or list of allowed attribute names

    def __init__(self, x, y):
        self.x = x
        self.y = y

# p.z = 1   → AttributeError: 'Point' object has no attribute 'z'
# vars(p)   → AttributeError: no __dict__

Class Introspection

isinstance(obj, ClassName)          # True if obj is instance of ClassName or subclass
issubclass(Sub, Parent)             # True if Sub is subclass of Parent
type(obj) is ClassName              # exact type check (no inheritance)
type(obj).__name__                  # class name as string

obj.__class__                       # same as type(obj)
ClassName.__bases__                 # direct parent classes
ClassName.__mro__                   # full MRO tuple
ClassName.__dict__                  # class namespace dict
obj.__dict__                        # instance attribute dict (if no __slots__)
hasattr(obj, "method")
getattr(obj, "method", default)
setattr(obj, "attr", value)
dir(obj)                            # all attribute names

Mixins

class SerializeMixin:
    def to_dict(self):
        return self.__dict__.copy()

    def to_json(self):
        import json
        return json.dumps(self.to_dict())

class LogMixin:
    def log(self, msg):
        print(f"[{self.__class__.__name__}] {msg}")

class User(SerializeMixin, LogMixin):
    def __init__(self, name, email):
        self.name = name
        self.email = email

u = User("Alice", "alice@example.com")
u.to_dict()    # {'name': 'Alice', 'email': 'alice@example.com'}
u.log("hello") # [User] hello