Python 3 Deep Dive Part 4 Oop High Quality

Descriptors are the mechanism behind property(), classmethod(), and super(). They allow you to define reusable attribute logic.

A descriptor is a class that implements any of __get__, __set__, or __delete__.

When to NOT use metaclasses:
Almost always. Class decorators and __init_subclass__ (Python 3.6+) solve 99% of metaclass use cases more simply. python 3 deep dive part 4 oop high quality

__init_subclass__ example:

class Base:
    def __init_subclass__(cls, **kwargs):
        super().__init_subclass__(**kwargs)
        print(f"Subclass cls.__name__ created")

class Child(Base): pass

Python has no real access control. We rely on naming conventions: When to NOT use metaclasses: Almost always

Name mangling example:

class Foo:
    def __init__(self):
        self.__secret = 42
    def get_secret(self):
        return self.__secret

f = Foo() print(f._Foo__secret) # 42 – still accessible, but harder to accidentally access

High-quality wisdom: Do not overuse __ (double underscore). It breaks subclassing. Use _ for internal attributes and trust other developers. Python is a "consenting adults" language.


Implement these to integrate with language features:

| Feature | Dunder Method(s) | |-----------------------|--------------------------------------| | Object representation | __repr__, __str__ | | Container protocol | __len__, __getitem__, __setitem__ | | Callable objects | __call__ | | Context manager | __enter__, __exit__ | | Arithmetic ops | __add__, __sub__, __mul__, etc.| | Hashing / equality | __hash__, __eq__ | Name mangling example : class Foo: def __init__(self):

Example – a sequence‑like class:

class ShoppingCart:
    def __init__(self):
        self._items = []
    def __len__(self):
        return len(self._items)
    def __getitem__(self, index):
        return self._items[index]
    def __setitem__(self, index, value):
        self._items[index] = value