I'm doing some distributed computing in which several machines communicate under the assumption that they all have identical versions of various classes. Thus, it seems to be good design to make these classes immutable; not in the sense that it must thwart a user with bad intentions, just immutable enough that it is never modified by accident.
How would I go about this? For example, how would I implement a metaclass that makes the class using it immutable after it's definition?
>>> class A(object):
... __metaclass__ = ImmutableMetaclass
>>> A.something = SomethingElse # Don't want this
>>> a = A()
>>> a.something = Whatever # obviously, this is still perfectly fine.
Alternate methods is also fine, such as a decorator/function that takes a class and returns an immutable class.
Immutable Objects : These are of in-built types like int, float, bool, string, unicode, tuple. In simple words, an immutable object can't be changed after it is created. Mutable Objects : These are of type list, dict, set . Custom classes are generally mutable.
Objects of built-in type that are immutable are: Numbers (Integer, Rational, Float, Decimal, Complex & Booleans) Strings. Tuples.
If the old trick of using __slots__
does not fit you, this, or some variant of thereof can do:
simply write the __setattr__
method of your metaclass to be your guard. In this example, I prevent new attributes of being assigned, but allow modification of existing ones:
def immutable_meta(name, bases, dct):
class Meta(type):
def __init__(cls, name, bases, dct):
type.__setattr__(cls,"attr",set(dct.keys()))
type.__init__(cls, name, bases, dct)
def __setattr__(cls, attr, value):
if attr not in cls.attr:
raise AttributeError ("Cannot assign attributes to this class")
return type.__setattr__(cls, attr, value)
return Meta(name, bases, dct)
class A:
__metaclass__ = immutable_meta
b = "test"
a = A()
a.c = 10 # this works
A.c = 20 # raises valueError
Don't waste time on immutable classes.
There are things you can do that are far, far simpler than messing around with trying to create an immutable object.
Here are five separate techniques. You can pick and choose from among them. Any one will work. Some combinations will work, also.
Documentation. Actually, they won't forget this. Give them credit.
Unit test. Mock your application objects with a simple mock that handles __setattr__
as an exception. Any change to the state of the object is a fail in the unit test. It's easy and doesn't require any elaborate programming.
Override __setattr__
to raise an exception on every attempted write.
collections.namedtuple
. They're immutable out of the box.
collections.Mapping
. It's immutable, but you do need to implement a few methods to make it work.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With