Python 3 Deep Dive Part 4 Oop High Quality Instant
Most developers know __init__, but the real constructor is __new__.
Example: Singleton pattern using __new__:
class Singleton: _instance = None def __new__(cls, *args, **kwargs): if cls._instance is None: cls._instance = super().__new__(cls) return cls._instance
s1 = Singleton() s2 = Singleton() print(s1 is s2) # True
Why does this matter for high-quality code?
Overriding __new__ allows you to control instance creation (e.g., caching, pooling, immutables). Never mutate __new__ without good reason, but understand it.
The dynamic nature of __dict__ consumes significant memory. If you are creating millions of instances, you can optimize memory by using __slots__. This tells Python to use a static array for attributes instead of a dynamic dictionary.
class Optimized:
__slots__ = ['x', 'y'] # Fixed attribute set
def __init__(self, x, y):
self.x = x
self.y = y
o = Optimized(1, 2)
o.z = 3 # Raises AttributeError! Cannot add new attributes.
Trade-off: You save memory but lose the ability to dynamically add attributes. python 3 deep dive part 4 oop high quality
OOP’s greatest power is also its greatest danger: inheritance. High-quality OOP strictly follows the Liskov Substitution Principle: derived classes must be substitutable for their base classes without altering correctness.
In Python, everything is an object. Every integer, function, class, and module is an object allocated on the heap. Each object has:
class MyClass: pass
obj = MyClass() print(type(obj)) # <class 'main.MyClass'> print(type(MyClass)) # <class 'type'> – yes, classes are objects too!Most developers know __init__ , but the real
Understanding this is crucial: classes are runtime objects, not just compile-time blueprints.