3

I want to create an immutable class like dictionary in python. I have found the following solution on stackoverflow, but this object is value can be updated by using __dict__.update function. Is there way to block this action.

class Immutable(object):
    def __init__(self, **kwargs):
        """Sets all values once given
        whatever is passed in kwargs
        """
        for k, v in kwargs.items():
            object.__setattr__(self, k, v)

    def __setattr__(self, *args):
        """Disables setting attributes via
        item.prop = val or item['prop'] = val
        """
        raise TypeError('Immutable objects cannot have properties set after init')

    def __delattr__(self, *args):
        """Disables deleting properties"""
        raise TypeError('Immutable objects cannot have properties deleted')


x = Immutable(a=5)
print(x.a) # 5 as expected
x.__dict__.update({'a': 7}) # should raise error or update copy of x
print(x.a) # 7, thus object is still mutable

Solution

As DeepSpace has mentioned in the comment to block access to __dict__ by implementing __getattr__.

I have implemented following solution and it worked

class Immutable(object):
    def __init__(self, **kwargs):
        """Sets all values once given
        whatever is passed in kwargs
        """
        for k, v in kwargs.items():
            object.__setattr__(self, k, v)

    def __getattribute__(self, item):
        result = super(Immutable, self).__getattribute__(item)
        if item == '__dict__':
            return dict(**result)
        return result

    def __setattr__(self, *args):
        """Disables setting attributes via
        item.prop = val or item['prop'] = val
        """
        raise TypeError('Immutable objects cannot have properties set after init')

    def __delattr__(self, *args):
        """Disables deleting properties"""
        raise TypeError('Immutable objects cannot have properties deleted')


x = Immutable(a=5)
print(x.a) # 5
x.__dict__.update({'a': 7}) # update value on a copy of dict which has no effect
print(x.a) # 5 this time object value remain same
6
  • 4
    FWIW, dict is not immutable. Commented Jan 14, 2020 at 14:31
  • 2
    Does this answer your question? How to make an immutable object in Python? Commented Jan 14, 2020 at 14:32
  • 3
    Anyway, you can block access to __dict__ by implementing __getattr__ Commented Jan 14, 2020 at 14:32
  • __init__ is called after the object is created, which means adding attributes is only possible is self is mutable. Use __new__ to emphasize that your object is (quasi-)immutable. Commented Jan 14, 2020 at 14:35
  • stackoverflow.com/questions/11014262/… Commented Jan 14, 2020 at 14:36

1 Answer 1

0

You can add to slot the only property that you want in your class as under

class Immutable(object):
    def __init__(self, **kwargs):
        """Sets all values once given
        whatever is passed in kwargs
        """
        for k, v in kwargs.items():
            object.__setattr__(self, k, v)

    def __setattr__(self, *args):
        """Disables setting attributes via
        item.prop = val or item['prop'] = val
        """
        raise TypeError('Immutable objects cannot have properties set after init')

    def __delattr__(self, *args):
        """Disables deleting properties"""
        raise TypeError('Immutable objects cannot have properties deleted')

    __slots__ =('k')


x = Immutable(k=5)
print(x.k) # 5 as expected
x.__dict__.update({'k': 7}) # should raise error or update copy of x
print(x.a) # 7, thus object is still mutable

OUTPUT

5
Traceback (most recent call last):
  File "inmutable.py", line 24, in <module>
    x.__dict__.update({'k': 7}) # should raise error or update copy of x
AttributeError: 'Immutable' object has no attribute '__dict__'
Sign up to request clarification or add additional context in comments.

2 Comments

This will not solve my problem, because I don't want fixed number of attribute in the class, and after adding slots I can't add arbitrary attributes.
Just giving you another option . I think the answer you posted is the one that should be used most of the time, and also for your case, unless you are looking for some memory optimization because you are creating millions of this kind of immutable object.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.