Welcome, guest | Sign In | My Account | Store | Cart

Apply this decorator to a class with __slots__. Members will be mutable during the execution of __init__ but read-only afterwards.

Python, 29 lines
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
def immutable(mutableclass):
    """ Decorator for making a slot-based class immutable """

    if not isinstance(type(mutableclass), type):
        raise TypeError('@immutable: must be applied to a new-style class')
    if not hasattr(mutableclass, '__slots__'):
        raise TypeError('@immutable: class must have __slots__')

    class immutableclass(mutableclass):
        __slots__ = ()                      # No __dict__, please   

        def __new__(cls, *args, **kw):
            new = mutableclass(*args, **kw) # __init__ gets called while still mutable
            new.__class__ = immutableclass  # locked for writing now
            return new 

        def __init__(self, *args, **kw):    # Prevent re-init after __new__
            pass

    # Copy class identity:
    immutableclass.__name__ = mutableclass.__name__
    immutableclass.__module__ = mutableclass.__module__

    # Make read-only:
    for name, member in mutableclass.__dict__.items():
        if hasattr(member, '__set__'):
            setattr(immutableclass, name, property(member.__get__))

    return immutableclass

This decorator works by altering the __class__ after the instance is created to a subclass where all settable members are replaced with read-only descriptors. Of course, you can always set __class__ to the parent class again to make it read-write again.

Some ideas for improvements:

  • Use a metaclass instead of a decorator
  • Make it possible to inherit from an immutable class
Created by Oren Tirosh on Sun, 5 Aug 2012 (MIT)
Python recipes (4591)
Oren Tirosh's recipes (16)

Required Modules

  • (none specified)

Other Information and Tasks