From b4300d80c2e2d3dd1943b48ac1eabfe271940a15 Mon Sep 17 00:00:00 2001 From: Albin Sun Date: Fri, 23 Jun 2023 01:10:20 +0800 Subject: [PATCH] Post "Encapsulation in Python" --- .../2023-06-22-encapsulation_in_python.html | 14550 ++++++++++++++++ _posts/2023-06-22-encapsulation_in_python.md | 9 + .../2023-06-22-encapsulation_in_python.ipynb | 223 + 3 files changed, 14782 insertions(+) create mode 100644 _includes/posts/2023-06-22-encapsulation_in_python.html create mode 100644 _posts/2023-06-22-encapsulation_in_python.md create mode 100644 assets/posts/2023-06-22-encapsulation_in_python/2023-06-22-encapsulation_in_python.ipynb 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 @@ + + + + + +2023-06-22-encapsulation_in_python + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+ + +
+ + + + +
+
+
+ + + + +
+
+
+ + +
+ + + + +
+
+
+ + + + +
+
+
+
+
+ + + + + + + + + diff --git a/_posts/2023-06-22-encapsulation_in_python.md b/_posts/2023-06-22-encapsulation_in_python.md new file mode 100644 index 0000000..9262be4 --- /dev/null +++ b/_posts/2023-06-22-encapsulation_in_python.md @@ -0,0 +1,9 @@ +--- +layout: post +title: "Encapsulation in Python" +date: 2023-06-23 01:03:00 +0800 +tags: python +--- + + +{% include posts/2023-06-22-encapsulation_in_python.html %} diff --git a/assets/posts/2023-06-22-encapsulation_in_python/2023-06-22-encapsulation_in_python.ipynb b/assets/posts/2023-06-22-encapsulation_in_python/2023-06-22-encapsulation_in_python.ipynb new file mode 100644 index 0000000..4452fdf --- /dev/null +++ b/assets/posts/2023-06-22-encapsulation_in_python/2023-06-22-encapsulation_in_python.ipynb @@ -0,0 +1,223 @@ +{ + "cells": [ + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "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." + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## General Class\n", + "A general class looks like" + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "metadata": {}, + "outputs": [], + "source": [ + "class Person:\n", + " def __init__(self, name: str) -> None:\n", + " self.name = name" + ] + }, + { + "cell_type": "code", + "execution_count": 21, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'John'" + ] + }, + "execution_count": 21, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "p = Person(\"John\")\n", + "p.name" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Clearly, we can have some unexpected names..." + ] + }, + { + "cell_type": "code", + "execution_count": 22, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "123\n", + "[]\n" + ] + } + ], + "source": [ + "print(Person(123).name)\n", + "print(Person([]).name)" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Class with Property Protection\n", + "Depends on the purpose, if certain level of encapsulation is need, we can leverage the `property` decorator on getter and overloading setter method." + ] + }, + { + "cell_type": "code", + "execution_count": 23, + "metadata": {}, + "outputs": [], + "source": [ + "class StrictPerson:\n", + " def __init__(self, name: str) -> None:\n", + " self._name = None # where real value is\n", + " self.name = name # interface for getter and setter\n", + " \n", + " @property\n", + " def name(self) -> str:\n", + " return self._name\n", + " \n", + " @name.setter\n", + " def name(self, name: str) -> None:\n", + " if isinstance(name, str):\n", + " self._name = name\n", + " else:\n", + " raise ValueError(\"Name should be a string.\")" + ] + }, + { + "cell_type": "code", + "execution_count": 24, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Doe\n", + "John Wick\n" + ] + }, + { + "ename": "ValueError", + "evalue": "Name should be a string.", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mValueError\u001b[0m Traceback (most recent call last)", + "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[1;32m 3\u001b[0m \u001b[0msp\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mname\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m\"John Wick\"\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 4\u001b[0m \u001b[0mprint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0msp\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mname\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 5\u001b[0;31m \u001b[0msp\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mname\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;36m123\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", + "\u001b[0;32m\u001b[0m in \u001b[0;36mname\u001b[0;34m(self, name)\u001b[0m\n\u001b[1;32m 13\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_name\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mname\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 14\u001b[0m \u001b[0;32melse\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 15\u001b[0;31m \u001b[0;32mraise\u001b[0m \u001b[0mValueError\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"Name should be a string.\"\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", + "\u001b[0;31mValueError\u001b[0m: Name should be a string." + ] + } + ], + "source": [ + "sp = StrictPerson(\"Doe\")\n", + "print(sp.name)\n", + "sp.name = \"John Wick\"\n", + "print(sp.name)\n", + "sp.name = 123" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Since it's an assignment operation with one argument in it, the overloading name setter method will be used.\n", + "\n", + "Let's try to instantiate an object with unexpected name..." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [ + { + "ename": "ValueError", + "evalue": "Name should be a string.", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mValueError\u001b[0m Traceback (most recent call last)", + "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mStrictPerson\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;36m123\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", + "\u001b[0;32m\u001b[0m in \u001b[0;36m__init__\u001b[0;34m(self, name)\u001b[0m\n\u001b[1;32m 2\u001b[0m \u001b[0;32mdef\u001b[0m \u001b[0m__init__\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mname\u001b[0m\u001b[0;34m:\u001b[0m \u001b[0mstr\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;34m->\u001b[0m \u001b[0;32mNone\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 3\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_name\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;32mNone\u001b[0m \u001b[0;31m# where real value is\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 4\u001b[0;31m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mname\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mname\u001b[0m \u001b[0;31m# interface for getter and setter\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 5\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 6\u001b[0m \u001b[0;34m@\u001b[0m\u001b[0mproperty\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m\u001b[0m in \u001b[0;36mname\u001b[0;34m(self, name)\u001b[0m\n\u001b[1;32m 13\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_name\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mname\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 14\u001b[0m \u001b[0;32melse\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 15\u001b[0;31m \u001b[0;32mraise\u001b[0m \u001b[0mValueError\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"Name should be a string.\"\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", + "\u001b[0;31mValueError\u001b[0m: Name should be a string." + ] + } + ], + "source": [ + "StrictPerson(123)" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "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." + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Reference\n", + "1. https://en.wikipedia.org/wiki/Mutator_method\n", + "2. https://docs.python.org/3.6/library/functions.html?highlight=setter#property" + ] + } + ], + "metadata": { + "colab": { + "authorship_tag": "ABX9TyNMTe6QuzjH1w/PUyuUGaB0", + "collapsed_sections": [], + "name": "introduction_to_statistics.ipynb", + "provenance": [] + }, + "kernelspec": { + "display_name": "Python 3", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.15" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +}