What’s a friendly class? One that accepts sensible arguments, has a nice string representation, and supports equality checks. Read on to learn how to write them.
Unlike many programming languages, in Python we don't really need to invent our own classes. We can invent our own classes, but we don't strictly need to.
Instead of classes, we could store all our data within lists and dictionaries and store all our functionality in functions. Often, especially when your code is relatively simple, not using a class makes for more readable code.
Of course, at some point in your Python coding journey, you will probably find some opportunities to make classes. When you do make a class, make sure it's a friendly class.
Always make your classes friendlySo you've decided to make a class. How can you make your class more user-friendly?
Friendly classes have these 3 qualities:
Here's a fairly friendly Point class:
class Point:
def __init__(self, x, y, z):
self.x, self.y, self.z = x, y, z
def __repr__(self):
class_name = type(self).__name__
return f"{class_name}(x={self.x!r}, y={self.y!r}, z={self.z!r})"
def __eq__(self, other):
if not isinstance(other, Point):
return NotImplemented
return (self.x, self.y, self.z) == (other.x, other.y, other.z)
I don't call this class friendly because of how its implementation looks. This class is friendly because of how it behaves.
Friendly classes accept sensible arguments:
Friendly classes have a nice string representation:
>>> p
Point(x=1, y=2, z=3)
And friendly classes support sensible equality checks:
>>> q = Point(1, 2, 3)
>>> p == q
True
This all works thanks to our __init__, __repr__, and __eq__ methods.
Want to make a friendly class quickly? Try using Python's dataclasses.dataclass decorator.
Here's the same class as above, implemented using a dataclass:
from dataclasses import dataclass
@dataclass
class Point:
x: float
y: float
z: float
Just like any other class, you can add your own methods and properties to dataclasses.
For example, we could add a method that computes the distance to another point:
from dataclasses import dataclass
from math import sqrt
@dataclass
class Point:
x: float
y: float
z: float
def distance_to(self, other):
return sqrt(
(self.x - other.x)**2
+ (self.y - other.y)**2
+ (self.z - other.z)**2
)
>>> p = Point(1, 2, 3)
>>> q = Point(4, 5, 6)
>>> p.distance_to(q)
5.196152422706632
Dataclasses are an additional abstraction on top of Python's regular class syntax.
All abstractions come with trade-offs: some functionality is automatic, which means we get it for free, but it's also hidden from us.
If you ever wonder what it would take to write a class that's equivalent to a given dataclass, try my dataclass to regular class converter at https://pym.dev/undataclass.
That undataclass tool can be helpful for better appreciating dataclasses. It may also be helpful for writing better classes more quickly, even if you decide not to use a dataclass.
Not all friendliness is the sameNot every class needs a __eq__ method.
Some objects really don't need to be comparable to other objects with equality.
For example, it wouldn't make much sense to compare two open database connections or two logging objects for equality. For objects like these, identity (whether they're the exact same object) matters more than value equality (whether they represent the same data).
And not all objects even need a friendly string representation.
If you're making an object that has no sensible state to display, you could leave __repr__ undefined.
Python takes this approach with its many iterator objects:
>>> enumerate([])
<enumerate object at 0x76dd66978fe0>
But most classes would benefit from these 3 traits:
Friendliness doesn't just stop with __init__, __repr__, and (often) __eq__.
The __init__, __repr__, and __eq__ methods are the most common dunder methods, but Python's classes support over 100 other dunder methods.
If your class would benefit from one of Python's many other dunder methods, you should implement them. Don't go overboard though: only implement dunder methods that really make sense for your class!
For example, we could make our Point objects support tuple unpacking (and other forms of iterability) by adding a __iter__ method:
from dataclasses import astuple, dataclass
@dataclass
class Point:
x: float
y: float
z: float
def __iter__(self):
return iter(astuple(self))
This would allow our Point objects to work with tuple unpacking:
>>> p = Point(1, 2, 3)
>>> x, y, z = p
>>> print(x, y, z)
1 2 3
Don't overuse classes. But when you do write your own classes, make your classes friendly. Users of your custom classes will enjoy using your classes more when they're friendly.
Dataclasses allow us to create friendly classes while writing less boilerplate code.
Third-party libraries, like attrs, provide even more feature-rich class-creation helpers than the dataclasses module.
Even if you don't use them directly, dataclasses are a good measuring stick for your class-based code. The next time you create a class, be sure to ask yourself, "is my class at least as friendly as an equivalent dataclass?"
For each new class you make, either:
dataclasses or attrs)Strive to write friendly classes, with or without dataclasses, attrs, and other class-creation helpers.
| # | Наименование новости | Тональность | Информативность | Дата публикации |
|---|---|---|---|---|
| 1 | Find All Instances of a Class With gc.get_objects() | 0 | 10 | 02-08-2026 |
| 2 | Связывание абстрактных классов со свойствами | 0 | 7.66 | 24-02-2026 |
| 3 | What Every Python Developer Should Know About the CPython ABI | 0 | 10 | 19-07-2026 |
| 4 | What Every Dev Should Know About the CPython ABI | 0 | 8.6 | 27-07-2026 |
| 5 | fapost/support | 0 | 8.26 | 03-08-2026 |
| 6 | The Fastest Python Struct? | 0 | 10 | 27-06-2026 |
| 7 | Write a coding agent from first principles: better tools | 0 | 10 | 12-07-2026 |
| 8 | Строки в Python: всё не так просто, как кажется | 0 | 6.22 | 19-05-2026 |
| 9 | Gleam for Python Programmers | 0 | 10 | 19-07-2026 |
| 10 | mellea - writing generative programs | 0 | 10 | 19-07-2026 |