Skip to content

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:

__setattr__ = object.__setattr__
__delattr__ = object.__delattr__

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