Object-Oriented Programming: Classes, Objects & Dunder Methods
Python is an object-oriented language from its core. Learn what the explicit self parameter actually represents in CPython, how to differentiate instance attributes from shared class attributes, when to use@classmethod and @staticmethod, and how to harness magic dunder methods.
1. Anatomy of a Class: Why "self" is Explicit
In C++ or Java, the this pointer is implicitly passed behind the scenes. In Python, adhering to the principle "Explicit is better than implicit", the instance itself is passed explicitly as the first argument, customarily named self:
class BankAccount:
# Class Attribute (shared across all instances on the class object itself)
bank_name = "Global Financial Trust"
interest_rate = 0.04
def __init__(self, account_holder: str, initial_balance: float = 0.0):
# Instance Attributes (unique per object stored in self.__dict__)
self.account_holder = account_holder
self.balance = initial_balance
def deposit(self, amount: float) -> float:
if amount <= 0:
raise ValueError("Deposit amount must be positive.")
self.balance += amount
return self.balance
# When you call account.deposit(500), Python internally executes:
# BankAccount.deposit(account, 500)2. Instance Methods vs @classmethod vs @staticmethod
| Method Type | Decorator | First Parameter | Best Use Case |
|---|---|---|---|
| Instance Method | None | self (the instance) | Accessing and modifying instance state (self.balance). |
| Class Method | @classmethod | cls (the class) | Alternative factory constructors (e.g. from_json, from_csv). |
| Static Method | @staticmethod | None | Pure utility functions logically grouped inside the class namespace. |
class ServerNode:
total_nodes = 0
def __init__(self, hostname: str, ip_address: str):
self.hostname = hostname
self.ip_address = ip_address
ServerNode.total_nodes += 1
@classmethod
def from_connection_string(cls, conn_str: str):
"""Alternative constructor parsing 'hostname:ip'."""
host, ip = conn_str.split(":")
return cls(host, ip)
@staticmethod
def is_valid_ipv4(ip: str) -> bool:
"""Utility helper independent of any instance or class state."""
octets = ip.split(".")
return len(octets) == 4 and all(o.isdigit() and 0 <= int(o) <= 255 for o in octets)
node = ServerNode.from_connection_string("node-east-1:192.168.1.10")
print("Valid IP?", ServerNode.is_valid_ipv4("192.168.1.10"))3. Magic Dunder Methods: Making Classes Pythonic
"Dunder" (Double Underscore) methods allow your custom classes to intercept Python operators (like ==, +, len(), and string casting):
class Vector2D:
def __init__(self, x: float, y: float):
self.x = x
self.y = y
# __repr__ is for developers (unambiguous, matches constructor syntax)
def __repr__(self) -> str:
return f"Vector2D(x={self.x}, y={self.y})"
# __str__ is for human-readable end users
def __str__(self) -> str:
return f"({self.x}, {self.y})"
# Overload addition operator (+)
def __add__(self, other: "Vector2D") -> "Vector2D":
return Vector2D(self.x + other.x, self.y + other.y)
# Overload equality operator (==)
def __eq__(self, other: object) -> bool:
if not isinstance(other, Vector2D):
return False
return self.x == other.x and self.y == other.y
v1 = Vector2D(2, 3)
v2 = Vector2D(4, 5)
v3 = v1 + v2
print("v3 Representation:", repr(v3)) # Vector2D(x=6, y=8)
print("v3 Equals Vector2D(6, 8)?", v3 == Vector2D(6, 8)) # TrueExplore Related Tools
Hand-picked utilities and calculators related to this tool.
