简体   繁体   中英

Unchangeable Python Class Instance Attribute

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?

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM