Reference
freezable.Freezable
A class that allows instances to marked as "frozen" or "unfrozen."
When an instance is "frozen," it is treated as an immutable object; all mutating operations/methods are disabled.
By default, this class disables setting and deleting attributes to help
preserve the frozen guarantee. Note that this adds some overhead to each
set and delete. To remove this behavior (for performance or some other
reason), override the __setattr__
and __delattr__
methods with the ones
from object
:
This class can be used both in cases of single and multiple inheritance.
There is no need to call super().__init__()
in the subclass's __init__
method. You can call it, but it will not do anything.
Example: Freezable Stack
Here is an example of a freezable stack data structure:
from freezable import Freezable, enabled_when_unfrozen
class FreezableStack(Freezable):
def __init__(self):
self._data = []
#
# Mutating methods
#
# These methods use the @enabled_when_unfrozen decorator. This
# prevents the object from being mutated while the object is
# frozen.
@enabled_when_unfrozen
def push(self, x):
self._data.append(x)
@enabled_when_unfrozen
def pop(self):
return self._data.pop()
#
# Non-mutating methods
#
# These methods are non-mutating and can be used any time.
def is_empty(self):
return not bool(self._data)
def top(self):
return self._data[-1] if self._data else None
freeze()
Freezes this object. All methods/operations that could mutate this object become disabled.
unfreeze()
Unfreezes this object. All methods/operations that could mutate this object become re-enabled.
is_frozen()
Checks if this object is frozen.
Returns:
Type | Description |
---|---|
bool
|
True if this object is frozen; False otherwise. |
freezable.FrozenError
Bases: RuntimeError
Raised when an operation that could mutate a Freezable object is used when that object is frozen.
@freezable.enabled_when_unfrozen
Decorates a instance method to raise an FrozenError if the instance is frozen.
If the decorated instance method is run while the instance is frozen, a
FrozenError
raised and the inner method body is not executed.
It is required that the class that owns the instance method subclasses
the Freezable
class.
Example: Decorating Mutating Methods on a Freezable Stack
This is one example of using the decorator in a class. Here, the
decorator is used on the push
and pop
methods. This is to
prevent the instance from being mutated while frozen.
from freezable import Freezable, enabled_when_unfrozen
class FreezableStack(Freezable):
def __init__(self):
self._data = []
#
# Mutating methods
#
# These methods use the @enabled_when_unfrozen decorator. This
# prevents the object from being mutated while the object is
# frozen.
@enabled_when_unfrozen
def push(self, x):
self._data.append(x)
@enabled_when_unfrozen
def pop(self):
return self._data.pop()
#
# Non-mutating methods
#
# These methods are non-mutating and can be used any time.
def is_empty(self):
return not bool(self._data)
def top(self):
return self._data[-1] if self._data else None
Example usage of the freezable stack:
stk = FreezableStack()
assert stk.top() == None
stk.push(1)
assert stk.top() == 1
stk.push(2)
assert stk.top() == 2
stk.freeze()
try:
stk.push(3) # this raises FrozenError because stk is frozen
except FrozenError:
pass
assert stk.top() == 2 # stack was not modified
stk.unfreeze()
stk.push(3) # now we can push an element
assert stk.top() == 3