Python 3 Deep Dive Part 4 Oop High Quality [ BEST ]

Python 3 Deep Dive Part 4 Oop High Quality [ BEST ]

| Technique | Benefit | When to use | |------------------------------------|-------------------------------------------|------------------------------------------| | __slots__ | Reduces memory, faster attribute access | Many instances, fixed attributes | | @dataclass(frozen=True) | Immutable, auto __init__, __repr__ | Data containers without logic | | weakref for cycles | Prevents memory leaks | Observer patterns, caches | | __new__ override | Control instance creation (e.g., singleton)| Rare; use module‑level global instead |


Python does not have private, protected, or public keywords like Java/C++. Instead, it relies on convention and name mangling.

ABCs define interfaces. They are not for performance; they are for documentation and runtime checking.

from abc import ABC, abstractmethod

class Drawable(ABC): @abstractmethod def draw(self, canvas): pass

@classmethod
def __subclasshook__(cls, C):
    # Allow duck typing: any class with draw() is a Drawable
    if any("draw" in B.__dict__ for B in C.__mro__):
        return True
    return NotImplemented

class Circle: # No explicit inheritance def draw(self, canvas): print(f"Circle on canvas") python 3 deep dive part 4 oop high quality

print(issubclass(Circle, Drawable)) # True (thanks to subclasshook)

Built-in ABCs:

Real-world use: Define a plugin system where third-party code must implement certain methods. Register virtual subclasses with @Drawable.register. | Technique | Benefit | When to use


By default, == checks for value equality (calling __eq__), while is checks for identity (memory address via id()).

a = [1, 2]
b = [1, 2]
print(a == b)  # True (Values are equal)
print(a is b)  # False (Different objects in memory)

Every Python instance carries a hidden __dict__ (a hash table for attributes). This is flexible but memory-inefficient for millions of objects.

Enter __slots__: A declaration that freezes attribute names, replacing __dict__ with a C array.

Before – Profligate:

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

In languages like Java, private attributes are accessed via getters/setters. In Python, we start with public attributes and refactor to properties when needed.

Bad (Java-style):

class BadCircle:
    def __init__(self, radius):
        self._radius = radius
    def get_radius(self):
        return self._radius
    def set_radius(self, value):
        if value < 0:
            raise ValueError("Radius cannot be negative")
        self._radius = value

Good (Pythonic):

class Circle:
    def __init__(self, radius):
        self.radius = radius  # Uses setter if defined
@property
def radius(self):
    return self._radius
@radius.setter
def radius(self, value):
    if value < 0:
        raise ValueError("Radius cannot be negative")
    self._radius = value
@property
def area(self):
    return 3.14159 * self._radius ** 2

Key insight: Properties allow you to evolve an attribute into logic without changing the API. Your users still write circle.radius = 5, not circle.set_radius(5).