0

So I've been reading up on descriptors to try and get a better grasp of how they work and while I know you cannot really prohibit things in Python, the lightbulb lit up and this idea came to me (I remembered reading about instance bound descriptors here and borrowed the implementation):

class Immutable:
    __slots__ = "name"

    def __init__(self, name):
        def name_setter(obj, val):
            print("Cannot change name!")
        self.name = property(lambda obj: name, name_setter)

    def __setattr__(self, attr, value):
        try:
            # Try invoking the descriptor protocol __set__ "manually"
            got_attr = super().__getattribute__(attr)
            got_attr.__set__(self, value)
        except AttributeError:
            # Attribute is not a descriptor, just set it:
            super().__setattr__(attr, value)

    def __getattribute__(self, attr):
        # If the attribute does not exist, super().__getattribute__()
        # will raise an AttributeError
        got_attr = super().__getattribute__(attr)
        try:
            # Try "manually" invoking the descriptor protocol __get__()
            return got_attr.__get__(self, type(self))
        except AttributeError:
            # Attribute is not a descriptor, just return it:
            return got_attr


mark = Immutable("Mark White")
print(mark.name)

mark.name = "test1"
print(mark.name)

setattr(mark, "name", "test2")
print(mark.name)

mark.__setattr__("name", "test3")
print(mark.name)

jon = Immutable("Jon Snow")
print(jon.name)
print(mark.name)


Output:

Mark White
Cannot change name!
Mark White
Cannot change name!
Mark White
Cannot change name!
Mark White
Jon Snow
Mark White

The idea is that this restricts the name attribute from getting changed because it is created as a property whose setter is that function defined in __init__. Also, the custom __setattr__ and __getattribute__ functions allow the descriptor to be instance bound. So the value is set when the object is created and that's it. Even the __dict__ cannot be altered due to __slots__ being defined.

So my question is:

Am I not seeing something extremely obvious or is this attribute really not changeable?

1 Answer 1

1

No, this attribute is definitely changeable:

object.__setattr__(mark, 'name', 'Foo')

Will successfully set the name.

Not sure what the point of "instance bound" descriptors is. This would never pass any sane code review.

Sign up to request clarification or add additional context in comments.

1 Comment

Ah, and there it is. Makes sense that a parent's class setattr would work. Not really sure about the instance bound descriptors either. I just remembered stumbling upon that article a while back and looked it up again.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.