-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy path06-immutable-point-objects.py
More file actions
205 lines (137 loc) · 5.99 KB
/
06-immutable-point-objects.py
File metadata and controls
205 lines (137 loc) · 5.99 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
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
"""Question: Create a class ImmutablePoint that represents an immutable point in 2D space.
Override the __setattr__ method to prevent modification of attributes after initialization.
"""
# LEARNING CHALLENGE
#
# Before looking at any solution below, please try to solve this yourself first!
#
# Tips for success:
# - Read the question carefully
# - Think about what classes and methods you need
# - Start with a simple implementation
# - Test your code step by step
# - Don't worry if it's not perfect - learning is a process!
#
# Remember: The best way to learn programming is by doing, not by reading solutions!
#
# Take your time, experiment, and enjoy the learning process!
# Try to implement your solution here:
# (Write your code below this line)
# HINT SECTION (Only look if you're really stuck!)
#
# Think about:
# - What is the __setattr__ method and when is it called?
# - How can you allow setting attributes during initialization but prevent it afterwards?
# - What is super().__setattr__ and why might you need it?
# - How do you raise an appropriate exception for immutable objects?
#
# Remember: Start simple and build up complexity gradually!
# ===============================================================================
# STEP-BY-STEP SOLUTION
# ===============================================================================
#
# CLASSROOM-STYLE WALKTHROUGH
#
# Let's solve this problem step by step, just like in a programming class!
# Each step builds upon the previous one, so you can follow along and understand
# the complete thought process.
#
# ===============================================================================
# Step 1: Define the ImmutablePoint class
# ===============================================================================
# Explanation:
# Let's start by creating our ImmutablePoint class. This class will represent
# a point in 2D space that cannot be modified after creation.
class ImmutablePoint:
pass # We'll add methods next
# What we accomplished in this step:
# - Created the basic ImmutablePoint class structure
# Step 2: Add the constructor (__init__ method)
# ===============================================================================
# Explanation:
# The __init__ method needs to set the x and y coordinates. However, since we'll
# override __setattr__ to prevent modifications, we need a special way to set
# attributes during initialization.
class ImmutablePoint:
def __init__(self, x, y):
# We'll add attribute setting next
pass
# What we accomplished in this step:
# - Added constructor that accepts x and y coordinates
# Step 3: Set attributes using super().__setattr__
# ===============================================================================
# Explanation:
# We use super().__setattr__ to bypass our custom __setattr__ method during
# initialization. This allows us to set the initial values while still
# preventing future modifications.
class ImmutablePoint:
def __init__(self, x, y):
super().__setattr__('x', x)
super().__setattr__('y', y)
# What we accomplished in this step:
# - Used super().__setattr__ to set initial x and y values
# - Bypassed the custom __setattr__ method during initialization
# Step 4: Override __setattr__ to prevent modifications
# ===============================================================================
# Explanation:
# Now let's override the __setattr__ method to raise an exception whenever
# someone tries to modify any attribute after the object is created.
class ImmutablePoint:
def __init__(self, x, y):
super().__setattr__('x', x)
super().__setattr__('y', y)
def __setattr__(self, key, value):
raise AttributeError("Cannot modify immutable point")
# What we accomplished in this step:
# - Added __setattr__ override that prevents any attribute modifications
# - Raises AttributeError with descriptive message
# Step 5: Create an instance and test our class
# ===============================================================================
# Explanation:
# Finally, let's create an instance of our ImmutablePoint class and test it to make sure
# the immutability works correctly. We'll test both normal access and modification attempts.
class ImmutablePoint:
def __init__(self, x, y):
super().__setattr__('x', x)
super().__setattr__('y', y)
def __setattr__(self, key, value):
raise AttributeError("Cannot modify immutable point")
# Test our class:
point = ImmutablePoint(1, 2)
# Test reading attributes (should work)
print(f"Point coordinates: ({point.x}, {point.y})")
# Test modifying attributes (should raise exception)
try:
point.x = 3
print("ERROR: Modification should have failed!")
except AttributeError as e:
print(f"Good! Modification prevented: {e}")
# Test adding new attributes (should also fail)
try:
point.z = 5
print("ERROR: Adding new attribute should have failed!")
except AttributeError as e:
print(f"Good! New attribute prevented: {e}")
# What we accomplished in this step:
# - Created and tested our complete ImmutablePoint implementation
# - Verified that reading works but modification fails
# - Tested both existing and new attribute modifications
# ===============================================================================
# CONGRATULATIONS!
#
# You've successfully completed the step-by-step solution!
#
# Key concepts learned:
# - Understanding the __setattr__ method and when it's called
# - Using super().__setattr__ to bypass custom behavior during initialization
# - Creating immutable objects that prevent modification after creation
# - Proper exception handling for invalid operations
#
# Try it yourself:
# 1. Start with Step 1 and code along
# 2. Test each step before moving to the next
# 3. Understand WHY each step is necessary
# 4. Experiment with modifications (try adding a distance_from_origin method!)
#
# Remember: The best way to learn is by doing!
# ===============================================================================