GGistDev

Classes and Objects in Python

Everything is an object; classes define blueprints for creating objects with state and behavior.

Defining a class and instances

Use class to define attributes and methods; __init__ initializes instance state.

class User:
    def __init__(self, name: str, email: str) -> None:
        self.name = name
        self.email = email

    def greet(self) -> str:
        return f"Hello, {self.name}!"

u = User("Ada", "ada@example.com")

Instance vs class attributes

Instance attributes live on each object; class attributes are shared across instances.

class Counter:
    total = 0            # class attribute (shared)
    def __init__(self) -> None:
        self.count = 0   # instance attribute (per object)

Methods: instance, class, static

  • Instance methods receive self
  • Class methods receive cls and are marked with @classmethod
  • Static methods are namespaced utilities with no implicit first argument
class Math:
    @classmethod
    def from_str(cls, s: str) -> int:
        return int(s)

    @staticmethod
    def add(a: int, b: int) -> int:
        return a + b

Representation and printing

Define __repr__ for unambiguous debugging and __str__ for user‑friendly text.

class Point:
    def __init__(self, x: int, y: int) -> None:
        self.x, self.y = x, y
    def __repr__(self) -> str:
        return f"Point(x={self.x!r}, y={self.y!r})"
    def __str__(self) -> str:
        return f"({self.x}, {self.y})"

Equality and hashing

Implement __eq__ to compare by value; implement __hash__ only if the object is immutable and equality is value‑based.

class Card:
    def __init__(self, rank: str, suit: str):
        self.rank, self.suit = rank, suit
    def __eq__(self, other: object) -> bool:
        if not isinstance(other, Card):
            return NotImplemented
        return (self.rank, self.suit) == (other.rank, other.suit)
    def __hash__(self) -> int:
        return hash((self.rank, self.suit))

Properties (encapsulation)

Expose computed/validated attributes with @property.

class Temperature:
    def __init__(self, c: float):
        self._c = c
    @property
    def celsius(self) -> float:
        return self._c
    @celsius.setter
    def celsius(self, value: float) -> None:
        if value < -273.15: raise ValueError("below absolute zero")
        self._c = value

Dataclasses (boilerplate reduction)

@dataclass auto‑generates __init__, __repr__, __eq__, etc. Use frozen=True for immutability.

from dataclasses import dataclass
@dataclass(frozen=True)
class Point2D:
    x: int
    y: int

Slots (memory/perf)

__slots__ restricts dynamic attributes and reduces memory overhead.

class Light:
    __slots__ = ("on",)
    def __init__(self, on: bool):
        self.on = on

Summary

  • Define classes with clear state and methods; pick instance/class/static appropriately
  • Implement __repr__, __str__, equality, and properties for usability
  • Consider @dataclass and __slots__ for efficiency and clarity