diff --git a/_includes/posts/2023-06-22-encapsulation_in_python.html b/_includes/posts/2023-06-22-encapsulation_in_python.html new file mode 100644 index 0000000..645780d --- /dev/null +++ b/_includes/posts/2023-06-22-encapsulation_in_python.html @@ -0,0 +1,14550 @@ + + +
+ + +In OOP, setter and getter (mutator and accessor) methods is a common way to implement encapsulation which protects private variables. In Python, as we know, object properties are public, when we need to achieve property protection, the pythonic way is the property
decorator.
A general class looks like
+ +class Person:
+ def __init__(self, name: str) -> None:
+ self.name = name
+
p = Person("John")
+p.name
+
'John'+
Clearly, we can have some unexpected names...
+ +print(Person(123).name)
+print(Person([]).name)
+
123 +[] ++
Depends on the purpose, if certain level of encapsulation is need, we can leverage the property
decorator on getter and overloading setter method.
class StrictPerson:
+ def __init__(self, name: str) -> None:
+ self._name = None # where real value is
+ self.name = name # interface for getter and setter
+
+ @property
+ def name(self) -> str:
+ return self._name
+
+ @name.setter
+ def name(self, name: str) -> None:
+ if isinstance(name, str):
+ self._name = name
+ else:
+ raise ValueError("Name should be a string.")
+
sp = StrictPerson("Doe")
+print(sp.name)
+sp.name = "John Wick"
+print(sp.name)
+sp.name = 123
+
Doe +John Wick ++
+--------------------------------------------------------------------------- +ValueError Traceback (most recent call last) +<ipython-input-24-c4f5d3c50dca> in <module> + 3 sp.name = "John Wick" + 4 print(sp.name) +----> 5 sp.name = 123 + +<ipython-input-23-1dc003482362> in name(self, name) + 13 self._name = name + 14 else: +---> 15 raise ValueError("Name should be a string.") + +ValueError: Name should be a string.+
Since it's an assignment operation with one argument in it, the overloading name setter method will be used.
+Let's try to instantiate an object with unexpected name...
+ +StrictPerson(123)
+
+--------------------------------------------------------------------------- +ValueError Traceback (most recent call last) +<ipython-input-19-a65321deca47> in <module> +----> 1 StrictPerson(123) + +<ipython-input-17-1dc003482362> in __init__(self, name) + 2 def __init__(self, name: str) -> None: + 3 self._name = None # where real value is +----> 4 self.name = name # interface for getter and setter + 5 + 6 @property + +<ipython-input-17-1dc003482362> in name(self, name) + 13 self._name = name + 14 else: +---> 15 raise ValueError("Name should be a string.") + +ValueError: Name should be a string.+
From the traceback, we can see the self.name = name
in the 4th line is infact the initial setter and the real value stores in the self._name
property.