-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathexamples.py
More file actions
110 lines (84 loc) · 3.96 KB
/
Copy pathexamples.py
File metadata and controls
110 lines (84 loc) · 3.96 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
108
109
110
"""
Chapter 16: Operator Overloading
================================
Original implementations exploring the mechanics of infix operators,
the reverse operator fallback (__radd__), and rich comparisons.
Key concepts covered:
- Infix operators (__add__)
- The Reverse Fallback (__radd__)
- The NotImplemented singleton
- Rich Comparisons (__eq__)
"""
import sys
import math
from array import array
sys.stdout.reconfigure(encoding="utf-8")
def section(title: str) -> None:
print(f"\n{'=' * 60}\n=== {title}\n{'=' * 60}")
# ─────────────────────────────────────────────────────────────────────────────
# 1. Infix Operators & The Reverse Fallback
# ─────────────────────────────────────────────────────────────────────────────
class Vector:
def __init__(self, components):
self._components = tuple(components)
def __iter__(self):
return iter(self._components)
def __repr__(self):
return f"Vector{self._components}"
# --- Addition ---
def __add__(self, other):
"""Called for: Vector + <something>"""
try:
# Try to build a new Vector by zipping and adding components
pairs = zip(self, other, strict=False)
return Vector(a + b for a, b in pairs)
except TypeError:
# We don't know how to add this type. Tell Python to try the
# reverse operator (__radd__) on the OTHER operand!
return NotImplemented
def __radd__(self, other):
"""Called for: <something> + Vector (if <something> returned NotImplemented)"""
# Addition is commutative, so we can just delegate back to __add__
return self + other
# --- Multiplication (Scalar) ---
def __mul__(self, scalar):
try:
factor = float(scalar)
except ValueError:
return NotImplemented
return Vector(n * factor for n in self)
def __rmul__(self, scalar):
return self * scalar
# --- Rich Comparisons ---
def __eq__(self, other):
if isinstance(other, Vector):
return self._components == other._components
# If we return NotImplemented, Python will evaluate other.__eq__(self)
return NotImplemented
def demo_infix_operators() -> None:
section("Part 1: Infix Operators and Reverse Fallbacks")
v1 = Vector([1, 2, 3])
v2 = Vector([10, 20, 30])
# 1. Standard __add__
print(f"Vector + Vector: {v1 + v2}")
# 2. Duck Typing __add__ (Tuple is iterable, so zip() works!)
print(f"Vector + Tuple: {v1 + (100, 200, 300)}")
# 3. The Reverse Fallback (__radd__)
# Tuple.__add__(Vector) returns NotImplemented.
# Python then successfully executes Vector.__radd__(Tuple).
print(f"Tuple + Vector: {(100, 200, 300) + v1}")
# 4. Scalar multiplication
print(f"Vector * 5: {v1 * 5}")
print(f"5 * Vector: {5 * v1}")
def demo_comparisons() -> None:
section("Part 2: Rich Comparisons")
v1 = Vector([1, 2])
v2 = Vector([1, 2])
print(f"v1 == v2: {v1 == v2}")
print(f"v1 == [1, 2]: {v1 == [1, 2]} (Returned NotImplemented, evaluated to False)")
# ─────────────────────────────────────────────────────────────────────────────
# MAIN
# ─────────────────────────────────────────────────────────────────────────────
if __name__ == "__main__":
demo_infix_operators()
demo_comparisons()