Search code examples
pythonvalidationoopencapsulationsetter

How to restrict certain attribute to be changed from the outside but to save the validation in Python


class Town:
     
    def __init__(self, name: str, country: str, population: int):

        #assert len(name) > 1, "The name of the town must be at least two characters long"
        self.name = name
        self.county = country
        self.population = population

    @property
    def name(self):
        return self.__name

    @name.setter
    def name(self,value):
        if len(value) < 2 or len(value) > 50:
            raise ValueError("The Name of the town must be between 2 and 50 characters")
        self.__name = value

For example I want to restrict the name attribute to be changed from the outside. Now it is possible with this name.setter. If i remove this setter it will work as I want but I will loose validations that I was made in the setter. What is the best way to keep aplying my validations for name attribute but not to be changed from the outside


Solution

  • It sounds like you want to set the name once, and then make it immutable. So do exactly that in __init__ and remove the setter:

    class Town:
        def __init__(self, name: str, country: str, population: int):
            if len(name) < 2 or len(name) > 50:
                raise ValueError("The Name of the town must be between 2 and 50 characters")
    
            self.__name = name
            self.county = country
            self.population = population
    
        @property
        def name(self):
            return self.__name
    

    If you want it to be internally modifiable somehow, use a private method to set it:

    class Town:
        def __init__(self, name: str, country: str, population: int):
            self.__set_name(name)
            self.county = country
            self.population = population
    
        def __set_name(self, value):
            if len(value) < 2 or len(value) > 50:
                raise ValueError("The Name of the town must be between 2 and 50 characters")
            self.__name = value
    
        @property
        def name(self):
            return self.__name