We can't find the internet
Attempting to reconnect
Something went wrong!
Attempting to reconnect
← Everyday Standard Library Tools step 39 of 55
Change an Attribute for One Block and Put It Back
Build temp_attr, a context manager that sets an attribute for the length
of a with block and then puts back what was there before. Tests use a
helper like this to switch a setting for a few lines.
holder = Holder()
setattr(holder, "mode", "prod")
with temp_attr(holder, "mode", "test"):
getattr(holder, "mode") # "test"
getattr(holder, "mode") # "prod"
What to write
Fix temp_attr(obj, name, value) in the starter. It is a generator function
decorated with @contextmanager.
- On entry, save the attribute's current value, then set it to
value. - On exit, put the saved value back. If the attribute did not exist before, delete it instead.
- Restore it on a normal exit and when the block raises. After restoring, let the exception reach the caller.
- Tell a missing attribute from one set to
None. Use a sentinel such as_MISSING = object()as the default forgetattr, notNone.
The starter has both bugs. It uses None as its missing marker, and it
restores only after a normal exit.
Then write solve. It creates a Holder, sets each key of initial on it
as an attribute, and then does these steps:
- Enter
temp_attr(obj, name, value)and append the attribute's value to a list calledseen. - If
nested_valueis notNone, enter a secondtemp_attrwithnested_valueinside the first. Append the value inside it, then append the value again after the inner block ends. OnlyNoneskips this step.False,0and""still nest. - If
raise_insideis true, raiseRuntimeErrorinside the outer block. Catch it outside thewithstatement. - If
reuseis true, create one more context manager withtemp_attr(obj, name, value)and keep it in a variable. Enter it once with an empty body, then try to enter the same object again. Catch anyExceptionfrom the second entry. Add nothing toseenin this step.
solve returns:
| Key | Value |
|---|---|
seen |
The values from steps 1 and 2, in order |
propagated |
True if the RuntimeError came out of the outer block, otherwise False |
has_after |
Whether the attribute exists after all the steps |
after |
Its value then, or None if it does not exist |
reuse_rejected |
True if the second entry raised. False when reuse is false |
Edge cases
- With
initial={"mode": "prod"},value="test"andnested_value="inner",seenis["test", "inner", "test"]andafteris"prod", whether or notraise_insideis true. - If the attribute did not exist at the start,
has_afterisFalseandafterisNone. - If it held
Noneat the start,has_afterisTrueandafterisNone.
Your code, saved here
Sign in to access your accepted solutions and saved draft history. You can keep reading the lesson without an account.
Sign in to your accountStuck?
Python reference solution
Sign in to track your attempts toward unlocking the reference solution.