easy +8 pts

Lock Context Manager

Implement a non-reentrant Lock class supporting the context manager protocol.

Implement a class `Lock` that provides a simple non-reentrant lock for coordinating access to shared resources. The class must support the context manager protocol (i.e., `with lock:`). Define the class `Lock` with the following methods: - `__init__(self)`: Initialize the lock state as not acquired. - `acquire(self)`: If the lock is already acquired, raise a `RuntimeError` with the message "Lock already acquired". Otherwise, mark the lock as acquired. This method does not block. - `release(self)`: If the lock is not currently acquired, raise a `RuntimeError` with the message "Lock not acquired". Otherwise, mark the lock as not acquired. - `__enter__(self)`: Call `acquire()` and return `self`. - `__exit__(self, exc_type, exc_val, exc_tb)`: Call `release()` and return `False` (so exceptions propagate). The lock is non-reentrant: attempting to acquire it while already held raises an error. There is no need for actual thread safety; just track the state with a boolean attribute. Your implementation should not import any modules. The test harness will run several functions that instantiate `Lock` and verify behavior. Specifically, your solution must define the following helper functions (they will be called directly by the tests): - `test_lock_initial_state()`: Create a `Lock` and return `True` if the lock is NOT acquired (i.e., `lock._locked == False`), otherwise return `False`. - `test_acquire_release()`: Create a `Lock`, call `acquire()` then `release()`, and return `True` if the lock is NOT acquired afterwards (i.e., `lock._locked == False`), otherwise return `False`. - `test_double_acquire()`: Create a `Lock`, call `acquire()` then attempt a second `acquire()`; catch the `RuntimeError` and return its message (string). - `test_double_release()`: Create a `Lock` and attempt `release()` without acquiring; catch the `RuntimeError` and return its message (string). - `test_release_then_reacquire()`: Create a `Lock`, call `acquire()`, `release()`, then `acquire()` again; return `True` if the lock is acquired (i.e., `lock._locked == True`), otherwise return `False`. - `test_context_manager()`: Use `with Lock() as l:` and return `True` if the lock is NOT acquired after the block (i.e., `l._locked == False`), otherwise return `False`. These helper functions serve as the test entry points; you do not need to call them yourself.

Constraints

No external imports are allowed. The class must only use a boolean attribute to track the lock state. All methods must behave as specified. The helper functions must be defined at module level.

Example

>>> lock = Lock()
>>> with lock:
...     print('inside')
...
inside
>>> try:
...     lock.acquire()
...     lock.acquire()
... except RuntimeError as e:
...     print(e)
...
Lock already acquired
>>> lock.release()
>>> try:
...     lock.release()
... except RuntimeError as e:
...     print(e)
...
Lock not acquired
8 points ~12 min

Recent Submissions

No submissions yet — hit Run Tests to try!

Hints

Use a boolean flag in __init__ to track whether the lock is held.
In acquire, check the flag and raise RuntimeError if already True; otherwise set it to True.
In release, check the flag and raise RuntimeError if already False; otherwise set it to False.
__enter__ should return self after calling acquire; __exit__ should always call release and return False.
For the helper functions, simply instantiate Lock and follow the scenario; use try/except to capture error messages.
Python 3
All tests passed!
Test Results
Press Ctrl+Enter or click Run Tests to execute your code.