-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathexamples.py
More file actions
107 lines (80 loc) · 4.25 KB
/
Copy pathexamples.py
File metadata and controls
107 lines (80 loc) · 4.25 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
"""
Chapter 14: Inheritance: For Better or For Worse
================================================
Original implementations exploring the dangers of subclassing built-in
types (the C-trap), Method Resolution Order (MRO), and cooperative super().
Key concepts covered:
- The Built-in Subclassing Trap (dict vs UserDict)
- Cooperative Multiple Inheritance
- The Diamond Problem and __mro__
- Mixin Classes
"""
import sys
from collections import UserDict
sys.stdout.reconfigure(encoding="utf-8")
def section(title: str) -> None:
print(f"\n{'=' * 60}\n=== {title}\n{'=' * 60}")
# ─────────────────────────────────────────────────────────────────────────────
# Part 1: The Built-in Subclassing Trap
# ─────────────────────────────────────────────────────────────────────────────
# CPython's native C implementation of `dict` often bypasses Python-level
# method overrides for performance.
class DoppelDict(dict):
"""Subclassing dict directly: A recipe for silent bugs."""
def __setitem__(self, key, value):
# We want to intercept all writes and append a warning
super().__setitem__(key, [value] * 2)
class SafeDict(UserDict):
"""Subclassing UserDict: Safe and compliant."""
def __setitem__(self, key, value):
super().__setitem__(key, [value] * 2)
def demo_built_in_trap() -> None:
section("Part 1: The Built-in Subclassing Trap")
# Direct assignment works for both
dd = DoppelDict(one=1)
dd['two'] = 2
sd = SafeDict(one=1)
sd['two'] = 2
# BUT! Look what happens when internal C methods update the dict!
dd.update(three=3)
sd.update(three=3)
print(f"Subclassing `dict`: {dd}")
print(f"Subclassing `UserDict`: {sd}")
print("\nNotice how `DoppelDict.update()` completely ignored our __setitem__!")
print("The C implementation of dict.update bypasses Python overrides.")
# ─────────────────────────────────────────────────────────────────────────────
# Part 2: Cooperative Multiple Inheritance & MRO
# ─────────────────────────────────────────────────────────────────────────────
# Python resolves the Diamond Problem using the C3 Linearization Algorithm.
# `super()` does NOT mean "parent class". It means "the next class in the MRO."
class Root:
def ping(self):
print(f" {self.__class__.__name__}.ping() in Root")
class A(Root):
def ping(self):
print(f" {self.__class__.__name__}.ping() in A -> delegating...")
super().ping()
class B(Root):
def ping(self):
print(f" {self.__class__.__name__}.ping() in B -> delegating...")
super().ping()
class Leaf(A, B):
def ping(self):
print(f" {self.__class__.__name__}.ping() in Leaf -> delegating...")
super().ping()
def demo_mro() -> None:
section("Part 2: Multiple Inheritance & The MRO")
leaf = Leaf()
print("MRO of Leaf:")
for cls in Leaf.__mro__:
print(f" - {cls.__name__}")
print("\nExecuting ping() across the diamond:")
leaf.ping()
print("\nNotice how `super().ping()` in Class A didn't call Root!")
print("It called Class B! `super()` delegates to the NEXT class in the MRO.")
# ─────────────────────────────────────────────────────────────────────────────
# MAIN
# ─────────────────────────────────────────────────────────────────────────────
if __name__ == "__main__":
demo_built_in_trap()
demo_mro()