0

I've started learning Python recently, and there are some topics I cannot really understand. One is the usage of the decorators in user defined objects, or encapsulation more generally. I mean, let's consider for example:

class Dog:
   def __init__(self,name,age):
      self.name=name
      self.age=age

Ok so now I have the object 'Dog'. If I make its attribute privates by adding '__' in the constructor, I won't be able to access them. In order to do so, I will have to use, for example, the decorator 'property', which has attributes (not sure how to call them actually)'getter', 'setter' and 'deleter'. So I make, for example, the name private. I have:

class Dog:
   def __init__(self,name,age):
      self.__name=name
      self.age=age
   @property
   def name(self):
      return self.__name
   @name.setter
   def name(self,name)
      self.__name=name
   @name.deleter
   def name(self)
      del self.__name

Now the question is: how is this different from just letting name be public? I would understand if I could only read the name value, or don't delete it, but if I give the user the possibility to read, write and delete the attribute... why do I bother making it private in the first place?

I don't know, maybe this was just a "syntax exercise" and in fact you are meant to give the user only a proper subset of those abilities.

7
  • 2
    It's not different (except that it's slightly less efficient). There's absolutely no point to the properties if they don't have any logic in them. The whole benefit is that you don't have to write getters and setters upfront and can add a layer of abstraction, if needed, without changing the API.
    – jonrsharpe
    Commented Jan 7, 2022 at 17:57
  • So you are only meant to use this encapsulation only when you don't want the user to do all that stuff? Like, for instance if you want the user to be able to only read an attribute
    – tommy1996q
    Commented Jan 7, 2022 at 18:00
  • Yes, or if you want to add validation to the value being set.
    – jonrsharpe
    Commented Jan 7, 2022 at 18:05
  • (Also note you shouldn't use __name_mangling unless that's really the specific behaviour you want: python.org/dev/peps/pep-0008/#designing-for-inheritance).
    – jonrsharpe
    Commented Jan 7, 2022 at 18:12
  • 1
    Validation is like saying "Stephen" isn't a valid name for a dog, so the assignment should fail. If you look up name mangling in Python there are good explanations on e.g. SO, it's to stop subclasses accessing attributes so isn't generally a good idea.
    – jonrsharpe
    Commented Jan 7, 2022 at 21:16

2 Answers 2

3

Here's a more thorough example of why you would want to have a private attribute: data type validation (as pointed out by the other answers).

Let's say that you've been using the Dog class for a few weeks, and a new bug has come up that happens when the name attribute is (for whatever reason) set to a value that's not a string. You now need to change the code in order to enforce that a Dog's name is indeed a string, by raising an informative Exception. How do you do that?

Your first idea may be to simply check the name's data type after creating a new Dog (using the isinstance builtin function):

my_dog = Dog(name='Max', age=5)
if not isinstance(my_dog.name, str):
    raise ValueError("The Dog's name is not a string")

This works, but there's a clear issue here: you need to 1) change every line of code where a Dog is created, and 2) you need to tell anyone who ever uses your Dog class that, by the way, remember to check for the name's data type. This is clearly a lot of work, and not future-proof by any means - what if you or another user forgets to do this check? What if no one ever reads your documentation on the Dog class?

You may then think to perform this check in the __init__ method:

def class Dog:
    def __init__(self, name, age):
        if not isinstance(name, str):
            raise ValueError("The Dog's name is not a string")
        self.__name = name
        self.age = age

This cuts down on the work, but it doesn't stop someone from modifying the Dog's name after it was instantiated:

my_dog = Dog(name='Max', age=5)
my_dog.name = 10  # oops, wrong value!

What we want to do is to actually move this type-checking functionality to a method that runs every time the name attribute gets set - which is exactly what the setter method (the one decorated with the @name.setter decorator) does:

def class Dog:
    def __init__(self, name, age):
        self.__name = name
        self.age = age

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

    @name.setter
    def name(self, new_name)
        if not isinstance(new_name, str):
            raise ValueError("The Dog's name is not a string")
        self.__name = new_name

Now the name's data type is always checked for, both during instantiation (in the __init__ method) and afterwards.

Data type validation is simply an example. The point of using private attributes and their getters/setters is to combine attribute access with some custom functionality. If you desire no functionality whatsoever when accessing/modifying the attribute, you're correct in your observation that you don't need to bother making it private and writing the getter/setter methods in the first place.

5

The advantage of properties is that from the viewpoint of the user of your class, it's syntactically the same as plain attribute access. So you can add logic (validation etc.) at any time without changing the class's interface and breaking the code that uses it. You can even swap in different versions of the class (e.g. with properties that do logging during development, without properties for production) and the caller won't even notice.

Contrast this to a language like Java where best practice is to always write getter/setter methods even if you don't need them, because you might need them later, but can't add them later without changing the API and thereby breaking code that uses the class.

BTW, there are no truly private attributes in Python. The leading __ is intended to keep names from conflicting among subclasses of the base class, where that might be a problem.

2
  • I...kinda lost you, but I get that it's pretty useful. Don't know what you mean by validation and I don't know Java, but thanks!
    – tommy1996q
    Commented Jan 7, 2022 at 21:16
  • 3
    Validation refers to the fact that a setter could make sure that the property is assigned the correct type of data with an acceptable value. for example a month property could be constrained to integers only and values of 1-12
    – kindall
    Commented Jan 7, 2022 at 22:11

Your Answer

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

Not the answer you're looking for? Browse other questions tagged or ask your own question.