ICS 33 Spring 2025
Exercise Set 8
Due date and time: Friday, June 6, 11:59pm
Final late work deadline: Late submissions are not accepted
Getting started
First of all, be sure that you've read the Reinforcement Exercises page, which explains everything you'll need to know, generally, about how the reinforcement exercises will work this quarter. Make sure you read that page before you continue with this one.
Problem 1 (3 points)
Earlier this quarter, we saw that Python provides a built-in decorator @classmethod
, which specifies that a method in a class shouldn't be subject to the usual rules that it be called on an object of that class and that this target object be passed into a leading self
parameter. Instead, the class is passed into a leading cls
parameter. When we first learned about this technique, it was somewhat magical; we had no way to explain how it might work, because we lacked the understanding of the details that underlie it. However, we're not in that position anymore, so it's worth revisiting that idea to make sure we understand how it relates to things we've learned in the weeks since. What better way to understand how it works than to implement it using the techniques we've since learned?
Write a decorator named @class_method
that, when used on a function defined within a class (i.e., a def
statement nested immediately within a class
statement), converts it into a class method, meaning two things.
self
parameter, it has a cls
parameter.When you've finished with it, you'd expect it to work as follows.
>>> class Thing:
... @class_method
... def foo(cls, x, y):
... return (cls.__name__, x + y)
...
>>> Thing.foo(11, 7)
('Thing', 18)
>>> Thing().foo(11, 7)
('Thing', 18)
It's safe to assume that your @class_method
decorator will only be used on methods (i.e., on def
statements immediately nested within class
statements). It is irrelevant how it works when it's used anywhere else.
Limitations
The Python standard library is entirely off-limits in this problem. Your function must not require any module to be imported.
Built-in decorators, such as @classmethod
or @staticmethod
, are also off-limits, since that's what we're asking you to implement here.
What to submit
Submit one Python script named problem1.py
, which contains your decorator and nothing else. Neither docstrings, comments, nor type annotations are required, since we've all agreed already on what problems we're solving here.
There is no credit being offered for writing automated tests — though you certainly might want to, since that's a great way to ensure that your code works as you expect — and we'd prefer you not submit them even if you do.
Problem 2 (2 points)
During our conversation about Class Design, we learned about three dunder methods that allow a class to modify how attribute lookup rules are applied to its objects: __getattr__
, __setattr__
, and __delattr__
. One difference that emerged between them is the circumstances in which they're used; we could summarize that difference as follows.
__getattr__
is called only if looking up an attribute in an object's dictionary fails (i.e., if that attribute is not present).__setattr__
and __delattr__
are called regardless of whether the attribute is present in the object's dictionary.In no more than a couple of sentences, briefly explain why you think Python handles __getattr__
differently from __setattr__
and __delattr__
, rather than handling all of these dunder methods identically.
What to submit
Submit one PDF named problem2.pdf
, which contains your answer to this question.
Problem 3 (3 points)
Write a class named LimitedString
meeting the following requirements.
LimitedString
requires one positional argument that specifies a maximum length. This maximum length must be a non-negative integer; anything else should cause a ValueError
to be raised.LimitedString
object is a descriptor that can be used to enforce that an object attribute's value is a string, and that its length is no longer than the maximum length.can_delete
is passed when constructing a LimitedString
, it controls whether an attribute described by it can be deleted from an object — True
if it can, or False
if it cannot. (If can_delete
is False
, deleting the attribute causes an AttributeError
to be raised.)After you're finished, you would expect the following behavior from it.
>>> class Thing:
... name = LimitedString(10)
...
>>> t = Thing()
>>> t.name = 'Boo'
>>> t.name
'Boo' # Strings fewer than 10 characters in length are fine.
>>> t.name = 'Boo is perfect this afternoon'
Traceback (most recent call last):
...
ValueError: ...
# Strings longer than 10 characters cannot be stored.
>>> t.name = 13
Traceback (most recent call last):
...
ValueError: ...
# Non-strings cannot be stored.
>>> del t.name
>>> t.name
Traceback (most recent call last):
...
AttributeError: ...
# After being deleted (or before having a value stored in them),
# attributes do not exist.
>>> class Person:
... name = LimitedString(10, can_delete = False)
... def __init__(self, name):
... self.name = name
...
>>> p = Person('Boo')
>>> p.name
'Boo'
>>> del p.name
Traceback (most recent call last):
...
AttributeError: ...
# Cannot delete LimitedString attributes when can_delete is False.
Limitations
The Python standard library is entirely off-limits in this problem. Your function must not require any module to be imported.
What to submit
Submit one Python script named problem3.py
, which contains your class and nothing else. Neither docstrings, comments, nor type annotations are required, since we've all agreed already on what problems we're solving here.
There is no credit being offered for writing automated tests — though you certainly might want to, since that's a great way to ensure that your code works as you expect — and we'd prefer you not submit them even if you do.
Problem 4 (2 points)
Background
Amidst a blizzard of assignments, their requirements, their due dates, and your grades on them — not to mention the concurrent blizzards in other courses you're taking alongside this one! — it's easy to forget why you're taking a course like this one, and what benefits you might derive from having come to the end of it. Our goal in offering this course is to broaden your perspective by deepening your understanding; though many of the lessons you've learned have been presented in terms of Python and its specifics, those lessons have their roots in a wider-ranging set of ideas, most of which would be just as applicable if this had been a course taught using another programming language.
So, it's our hope that you've emerged stronger than you were when you went in, in the big-picture sense as well as the small-picture one (i.e., as a programmer generally, but also as a Python programmer). Still, with so much of our focus having been on Python, it's worth stopping briefly to think about how far you've come, and how your point of view might have changed in the last ten weeks or so.
The question
This problem asks you to consider one question and write your thoughts about it.
You can write as much or as little as you'd like; we're not requiring you to write a chapter's worth of great literature here, but we also don't want you to feel like you can't explore your thoughts if you're on a roll. But do stay focused on the issue at hand: The focus is on how your views about Python have changed, rather than the logsitics of the course, your feelings about your grades, your interactions with course staff, and so on. The goal is to synthesize your thoughts about what you've learned, rather than getting yourself caught up in how you've learned it.
We can guarantee that we'll be grading this question by the "honest attempt" standard — there's no "correct" way to answer this, after all — though an honest attempt is one that actually engages with the stated question in some way (the "what you've learned" part), without veering into other matters (the "how you've learned it" part).
What to submit
Submit one PDF named problem4.pdf
, which contains your answer to this question.
Deliverables
In Canvas, you'll find a separate submission area for each problem. Submit your solution to each problem into the appropriate submission area. Be sure that you're submitting the correct file into the correct area (i.e., submitting your Problem 1 solution to the area for Problem 1, and so on). Under no circumstances will we offer credit for files submitted in the incorrect area.
Submit each file as-is, without putting it into a Zip file or arranging it in any other way. If we asked for a PDF, for example, all we want is a PDF; no more, no less. If you submit something other than what we asked for (e.g., a text file when we asked for a PDF, even if its filename ends in .pdf
), we will not be offering you any credit on the submission. There are no exceptions to this rule.
Of course, you should also be aware that you're responsible for submitting precisely the version of your work that you want graded. We won't regrade an exercise simply because you submitted the wrong version accidentally.
Can I submit after the deadline?
Unlike some of the projects in this course, the reinforcement exercises cannot be submitted after the deadline; there is no late policy for these. Each is worth only 2% of your grade, with the lowest score dropped — see the Reinforcement Exercises page for details — so it's not a disaster if you miss one of them along the way.
You're responsible for making a submission in order to receive credit, which means you'll want to be sure that you've remembered to submit your work and verify in Canvas that it's been received. A later claim of having forgotten to submit your work or having misremembered the due date will not be grounds for a resubmission under any circumstances.
What do I do if Canvas adjusts my filename?
Canvas will sometimes modify your filenames when you submit them (e.g., by adding a numbering scheme like -1 or a long sequence of hexadecimal digits to its name). In general, this is fine; as long as the file you submitted has the correct name prior to submission, we'll be able to obtain it with that same name, even if Canvas adjusts it.