Quark's Outlines: Python Basic Customization

Published: (January 17, 2026 at 07:11 AM EST)
4 min read
Source: Dev.to

Source: Dev.to

Overview, Historical Timeline, Problems & Solutions

When you make a class in Python, you can change how your objects behave in certain common situations. This is called Python basic customization. Python gives you special method names that begin and end with double underscores. These methods let you control what happens when your object is:

  • created
  • shown (printed)
  • compared
  • deleted
  • tested for truth

You do not call these methods yourself—Python calls them at the right time. You only define what they do.

Example: __init__ and __str__

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

    def __str__(self):
        return f"Hello, {self.name}!"

g = Greeter("Ada")
print(g)
# prints:
# Hello, Ada!

Here, Python calls __init__ when the object is created, and __str__ when it is printed.

Common Special (Magic) Methods

MethodWhen it runs
__init__Object creation
__del__Object deletion (when reference count reaches zero)
__str__print() or str()
__repr__repr() or interactive interpreter display
__cmp__Python 2: generic comparisons
__eq__, __lt__, __le__, __gt__, __ge__, __ne__Python 3: rich comparisons
__hash__When the object is used as a dictionary key or set element
__bool__ (or __nonzero__ in Python 2)Truth‑value testing (if obj:)

You can define any of these methods in your class to make your objects behave in helpful ways.

Hooking into Core Actions with Magic Methods

class Number:
    def __init__(self, value):
        self.value = value

    def __bool__(self):
        return self.value != 0

print(bool(Number(0)))   # False
print(bool(Number(5)))   # True

This object tells Python whether it should be treated as True or False based on its internal value.

Where Do Python’s Customization Methods Come From?

Python built its special methods on ideas from earlier object‑oriented languages.

YearMilestone
1980Smalltalk and C++ introduced special method names for construction, destruction, and string representation.
1989Python’s class model adopted __init__, __del__, and __str__.
1991Python 0.9.0 added __cmp__ and __repr__ for comparisons and debugging views.
1995Truth testing added __nonzero__ (later replaced by __bool__ in Python 3).
2001__hash__ rules refined in Python 2.2 for predictable dictionary behavior.
2008Python 3.0 removed __cmp__, replacing it with rich‑comparison methods (__eq__, __lt__, …).
2025Core method names are stable; recent changes focus on performance or internal use only.

How to Use Python Basic Customization the Right Way

Below are common problems and their solutions, each illustrating a particular magic method.

1. Run code when an object is created

Problem: You want the name to be saved at the moment the object is made, without calling a separate method later.

Solution: Define __init__.

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

u = User("Ada")
print(u.name)   # prints: Ada

2. Show a readable string when the object is printed

Problem: Printing an instance yields something like “. You want a clean, user‑friendly representation.

Solution: Define __str__.

class Report:
    def __init__(self, title):
        self.title = title

    def __str__(self):
        return f"Report: {self.title}"

r = Report("Q2 Sales")
print(r)   # prints: Report: Q2 Sales

3. Clean up resources when an object is destroyed

Problem: An object uses a file or network resource; you need to ensure it’s closed when the object is no longer needed.

Solution: Define __del__.

class Connection:
    def __del__(self):
        print("Connection closed.")

c = Connection()
del c          # prints: Connection closed.

Note: Relying on __del__ alone can be fragile (e.g., circular references). For deterministic cleanup, prefer context managers (with statements) and the __enter__/__exit__ protocol.

4. Compare objects

Problem: You have a class for items with prices and need to compare them.

Solution: In Python 3, implement the rich‑comparison methods you need (e.g., __lt__, __eq__).

class Item:
    def __init__(self, price):
        self.price = price

    def __lt__(self, other):
        return self.price < other.price

a = Item(10)
b = Item(15)
print(a < b)   # prints: True

If you need full ordering, you can inherit from functools.total_ordering and implement __eq__ plus one other comparison.

5. Use objects as dictionary keys

Problem: You want instances of a custom class to serve as keys in a dict, requiring a stable hash that respects equality.

Solution: Implement __hash__ (and __eq__) consistently.

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

    def __eq__(self, other):
        if not isinstance(other, Point):
            return NotImplemented
        return (self.x, self.y) == (other.x, other.y)

    def __hash__(self):
        return hash((self.x, self.y))

p1 = Point(1, 2)
p2 = Point(1, 2)
my_dict = {p1: "origin"}
print(my_dict[p2])   # prints: origin

Summary

Python’s magic methods (those with double underscores) let you hook into the language’s core operations—creation, representation, comparison, truth testing, hashing, and cleanup. By defining the appropriate methods in your classes, you can make your objects behave naturally and intuitively in everyday Python code.

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

    def __eq__(self, other):
        return self.x == other.x and self.y == other.y

    def __hash__(self):
        return hash((self.x, self.y))

p = Point(1, 2)
d = {p: "here"}
print(d[p])
# prints:
# here

Python calls __hash__ to find where the object should live in the dictionary.


Mike Vincent is an American software engineer and app developer from Los Angeles, California. More about Mike Vincent.

Back to Blog

Related posts

Read more »