<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:cc="http://cyber.law.harvard.edu/rss/creativeCommonsRssModule.html">
    <channel>
        <title><![CDATA[Stories by Amir Lavasani on Medium]]></title>
        <description><![CDATA[Stories by Amir Lavasani on Medium]]></description>
        <link>https://medium.com/@amirm.lavasani?source=rss-2e98894ce1bf------2</link>
        <image>
            <url>https://cdn-images-1.medium.com/fit/c/150/150/1*wHWuBeQF-hi9KFcxRmwYSg.jpeg</url>
            <title>Stories by Amir Lavasani on Medium</title>
            <link>https://medium.com/@amirm.lavasani?source=rss-2e98894ce1bf------2</link>
        </image>
        <generator>Medium</generator>
        <lastBuildDate>Sat, 20 Jun 2026 10:54:24 GMT</lastBuildDate>
        <atom:link href="https://medium.com/@amirm.lavasani/feed" rel="self" type="application/rss+xml"/>
        <webMaster><![CDATA[yourfriends@medium.com]]></webMaster>
        <atom:link href="http://medium.superfeedr.com" rel="hub"/>
        <item>
            <title><![CDATA[How to Add i18n to Your FastAPI App]]></title>
            <link>https://medium.com/@amirm.lavasani/how-to-add-i18n-to-your-fastapi-app-b546f7d183bb?source=rss-2e98894ce1bf------2</link>
            <guid isPermaLink="false">https://medium.com/p/b546f7d183bb</guid>
            <category><![CDATA[api]]></category>
            <category><![CDATA[python]]></category>
            <category><![CDATA[programming]]></category>
            <category><![CDATA[i18n]]></category>
            <category><![CDATA[fastapi]]></category>
            <dc:creator><![CDATA[Amir Lavasani]]></dc:creator>
            <pubDate>Wed, 26 Jun 2024 06:27:05 GMT</pubDate>
            <atom:updated>2024-08-14T17:27:06.482Z</atom:updated>
            <content:encoded><![CDATA[<h4>FASTAPI FOUNDATION SERIES</h4><h4>Part 4: Internationalization</h4><p>In today’s globalized world, reaching a wider audience often means offering your application in multiple languages.</p><p>By internationalizing your service, you make it more accessible to users worldwide, enhance the user experience, and potentially grow your user base.</p><p>By the end of this tutorial, your APIs will be able to deliver responses based on the user’s language preference.</p><h3>Introduction to Internationalization (i18n)</h3><p>Internationalization, or in short i18n, is the process of designing your application to support multiple languages.</p><p>It means adapting your app so it can be easily localized. This allows for translation and adjustments for different languages and regions without major code changes.</p><blockquote><strong>Internationalization</strong> is abbreviated as <strong>i18n</strong> because there are 18 letters between the first letter “i” and the last letter “n” in “internationalization.”</blockquote><h3>Internationalization vs. Localization 🌐</h3><p><strong>Internationalization (i18n) </strong>is about making your application capable of being localized by setting up the necessary infrastructure and ensuring flexibility.</p><p><strong>Localization (l10n)</strong> is the actual process of adapting your application for a specific language or region by translating text and adjusting other content to suit local preferences.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*ZKtJfq-zUSfj13VsLdbuPA.jpeg" /><figcaption>Dall-E generated image with the following concept: Lines of code transforming into a multilingual globe</figcaption></figure><h3>Setting Up i18n in FastAPI</h3><p>To add i18n capabilities to our FastAPI app, we will use three tools and concepts:</p><ol><li><strong>PyBabel</strong>: We’ll use the PyBabel package to extract, create, and compile translatable strings.</li><li><strong>Accept-Language Header</strong>: We’ll use the standard Accept-Language header to determine the user&#39;s preferred language for API responses.</li><li><strong>Custom Middleware</strong>: We’ll develop a custom middleware to handle requests and set the locale based on the request.</li></ol><h3>Understanding Gettext and PyBabel</h3><h4><strong>Gettext</strong></h4><p>Gettext is a powerful tool for managing translations in software applications. It allows you to mark strings in your code that need to be translated.</p><p>Then, it retrieves the appropriate translations based on the user’s language settings. Gettext is widely used because it simplifies the process of internationalization.</p><h4>PyBabel</h4><p>PyBabel is a Python library that works with Gettext. It helps extract translatable strings from your code, manage translation files, and compile them for use.</p><p>With PyBabel, you can easily create and update translation files, making the localization (l10n) process straightforward. PyBabel automates many tasks, making it an essential tool for Python developers working on multilingual applications.</p><h4>Understanding Translation File Formats: .pot, .po, and .mo</h4><p>Translation files are the backbone of the i18n process. Here’s a brief overview:</p><ul><li><strong>.pot (Portable Object Template)</strong>: <em>Template files that contain the original text strings from your application.</em></li><li><strong>.po (Portable Object)</strong>: <em>Files that contain the translated text strings for a particular language.</em></li><li><strong>.mo (Machine Object)</strong>: <em>Compiled binary files generated from .po files, used by the application at runtime.</em></li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*FVK5EpOEBDPSNEj-i-DE_A.jpeg" /><figcaption>Dall-E generated image with the following concept: A globe with interconnected nodes representing languages.</figcaption></figure><h3>Let’s Add i18n</h3><h4>1. Create a Simple API</h4><p>First, let’s look at a minimal FastAPI app. We will add internationalization so the user sees the greeting’s message in their preferred language.</p><pre>from fastapi import FastAPI<br>from pydantic import BaseModel<br><br>app = FastAPI()<br><br><br>class GreetingResponse(BaseModel):<br>    message: str<br><br><br>@app.get(&quot;/greetings&quot;, response_model=GreetingResponse)<br>async def greetings():<br>    return {&quot;message&quot;: &quot;Hello, this is a message in your language!&quot;}</pre><h4>2. Add i18n Module</h4><p>In this step, we will implement a translation mechanism using the gettext library.</p><p>This involves setting up a singleton class to manage translations, creating a middleware to detect the user’s preferred language, and providing a shorthand method for retrieving translated strings.</p><p>This will allow our FastAPI app to dynamically respond with messages in the user’s chosen language.</p><pre>import gettext<br>from pathlib import Path<br>from fastapi import Request<br><br><br>class TranslationWrapper:<br>    &quot;&quot;&quot;<br>    Singleton class for managing translations using gettext.<br><br>    This class initializes the translation object and provides<br>    a method for retrieving translated strings.<br><br>    Attributes:<br>        _instance (TranslationWrapper): The singleton instance of <br>        the TranslationWrapper class.<br>        translations (gettext.GNUTranslations): The translation <br>        object for managing translations.<br>    &quot;&quot;&quot;<br><br>    _instance = None<br><br>    def __new__(cls):<br>        &quot;&quot;&quot;<br>        Create a new instance of the class if it doesn&#39;t <br>        exist, otherwise return the existing instance.<br><br>        Returns:<br>            TranslationWrapper: The instance of the class.<br>        &quot;&quot;&quot;<br>        if cls._instance is None:<br>            cls._instance = super().__new__(cls)<br>            cls._instance.init_translation()<br>        return cls._instance<br><br>    def init_translation(self):<br>        &quot;&quot;&quot;<br>        Initialize the translation object.<br><br>        This method sets up the translation object <br>        using the default language and the specified <br>        translation directory.<br>        &quot;&quot;&quot;<br>        lang = &quot;en&quot;  # Default language<br>        # src/translation<br>        locales_dir = Path(__file__).parent / &quot;translations&quot;<br>        self.translations = gettext.translation(<br>            &quot;messages&quot;, <br>            localedir=locales_dir,<br>            languages=[lang],<br>            fallback=True<br>        )<br>        self.translations.install()<br><br>    def gettext(self, message: str) -&gt; str:<br>        &quot;&quot;&quot;<br>        Get the translated string for the specified message.<br><br>        Args:<br>            message (str): The message to be translated.<br><br>        Returns:<br>            str: The translated string.<br>        &quot;&quot;&quot;<br>        return self.translations.gettext(message)<br><br><br>async def set_locale(request: Request):<br>    &quot;&quot;&quot;<br>    Set the locale based on the request headers.<br><br>    This method retrieves the accept-language header <br>    from the request and sets the locale accordingly.<br><br>    Args:<br>        request (Request): The incoming request object.<br>    &quot;&quot;&quot;<br>    translation_wrapper = TranslationWrapper()<br><br>    lang = request.headers.get(&quot;Accept-Language&quot;, &quot;en&quot;)<br>    locales_dir = Path(__file__).parent / &quot;translations&quot;<br><br>    translation_wrapper.translations = gettext.translation(<br>        &quot;messages&quot;, localedir=locales_dir, languages=[lang], fallback=True<br>    )<br><br>    translation_wrapper.translations.install()<br><br><br>def _(message: str) -&gt; str:<br>    &quot;&quot;&quot;<br>    Get the translated string for the specified message.<br><br>    This method is a shorthand for calling gettext() and<br>    is used to retrieve translated strings.<br><br>    Args:<br>        message (str): The message to be translated.<br><br>    Returns:<br>        str: The translated string.<br>    &quot;&quot;&quot;<br>    translation_wrapper = TranslationWrapper()<br>    return translation_wrapper.gettext(message)</pre><h4>3. Add Language Middleware</h4><p>In this step, we add a custom middleware to our FastAPI application to set the language for each request.</p><p>The LanguageMiddleware class intercepts incoming requests and sets the language based on the Accept-Language header.</p><p>This middleware uses the set_locale function from the i18n module to determine and apply the appropriate language settings before passing the request to the next middleware or route handler.</p><pre>from fastapi import Request<br>from starlette.middleware.base import BaseHTTPMiddleware<br><br>from i18n import set_locale<br><br><br>class LanguageMiddleware(BaseHTTPMiddleware):<br>    &quot;&quot;&quot;<br>    Middleware for setting the language based on the <br>    request headers.<br><br>    This middleware sets the language of the application <br>    based on the Accept-Language header in the incoming <br>    request. It uses the set_locale function from the i18n <br>    module to determine the appropriate language for the request.<br><br>    Attributes:<br>        None<br>    &quot;&quot;&quot;<br><br>    async def dispatch(self, request: Request, call_next):<br>        &quot;&quot;&quot;<br>        Dispatch method to set the language for the request.<br><br>        This method intercepts incoming requests, sets the <br>        language based on the Accept-Language header, and then<br>        passes the request to the next middleware or route handler.<br><br>        Args:<br>            request (Request): The incoming request.<br>            call_next (Callable): The function to call to proceed<br>            to the next middleware or route handler.<br><br>        Returns:<br>            Response: The response generated by the next middleware<br>            or route handler.<br>        &quot;&quot;&quot;<br>        await set_locale(request)  # Set the language for the request<br>        response = await call_next(<br>            request<br>        )  # Proceed to the next middleware or route handler<br>        return response</pre><h4>4. Update API</h4><p>In this step, we update our FastAPI application to use i18n.</p><p>We add the custom LanguageMiddleware to the application to handle setting the language for each request based on the Accept-Language header.</p><p>Additionally, we update the /greetings endpoint to return a greeting message translated into the user&#39;s preferred language using the _ function from the i18n module.</p><pre>from fastapi import FastAPI<br>from pydantic import BaseModel<br>from i18n import _<br>from middleware import LanguageMiddleware<br><br><br>app = FastAPI()<br><br># add language middleware to FastAPI<br>app.add_middleware(LanguageMiddleware)<br><br><br>class GreetingResponse(BaseModel):<br>    message: str<br><br><br>@app.get(&quot;/greetings&quot;, response_model=GreetingResponse)<br>async def greetings():<br>    # i18n _(str) function to mark this string as translatable<br>    return {&quot;message&quot;: _(&quot;Hello, this is a message in your language!&quot;)}<br><br><br># To run the server, save this code to a file (e.g., app.py) and run:<br># uvicorn app:app --reload</pre><h4>5. Setup Translation Files</h4><p>Finally, create the translation folder and extract all the translatable strings using the following pybabel command:</p><pre>mkdir translations<br>pybabel extract -o ./translations/messages.pot .</pre><p>This will generate a translation catalog like this:</p><pre># Translations template for PROJECT.<br># Copyright (C) 2024 ORGANIZATION<br># This file is distributed under the same license as the PROJECT project.<br># FIRST AUTHOR &lt;EMAIL@ADDRESS&gt;, 2024.<br>#<br>#, fuzzy<br>msgid &quot;&quot;<br>msgstr &quot;&quot;<br>&quot;Project-Id-Version: PROJECT VERSION\n&quot;<br>&quot;Report-Msgid-Bugs-To: EMAIL@ADDRESS\n&quot;<br>&quot;POT-Creation-Date: 2024-06-19 13:50+0330\n&quot;<br>&quot;PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n&quot;<br>&quot;Last-Translator: FULL NAME &lt;EMAIL@ADDRESS&gt;\n&quot;<br>&quot;Language-Team: LANGUAGE &lt;LL@li.org&gt;\n&quot;<br>&quot;MIME-Version: 1.0\n&quot;<br>&quot;Content-Type: text/plain; charset=utf-8\n&quot;<br>&quot;Content-Transfer-Encoding: 8bit\n&quot;<br>&quot;Generated-By: Babel 2.14.0\n&quot;<br><br>#: main.py:19<br>msgid &quot;Hello, this is a message in your language!&quot;<br>msgstr &quot;&quot;</pre><p>Next, create the .po files for the languages you want to support. Here are the commands to create translation files for English, German, and French:</p><pre>pybabel init -i translations/messages.pot -d translations -l en<br>pybabel init -i translations/messages.pot -d translations -l fr<br>pybabel init -i translations/messages.pot -d translations -l de</pre><p>Now you need to translate the strings in each language. Here is an example for the French:</p><pre># French translations for PROJECT.<br># Copyright (C) 2024 ORGANIZATION<br># This file is distributed under the same license as the PROJECT project.<br># FIRST AUTHOR &lt;EMAIL@ADDRESS&gt;, 2024.<br>#<br>msgid &quot;&quot;<br>msgstr &quot;&quot;<br>&quot;Project-Id-Version: PROJECT VERSION\n&quot;<br>&quot;Report-Msgid-Bugs-To: EMAIL@ADDRESS\n&quot;<br>&quot;POT-Creation-Date: 2024-06-19 13:50+0330\n&quot;<br>&quot;PO-Revision-Date: 2024-06-19 14:11+0330\n&quot;<br>&quot;Last-Translator: FULL NAME &lt;EMAIL@ADDRESS&gt;\n&quot;<br>&quot;Language: fr\n&quot;<br>&quot;Language-Team: fr &lt;LL@li.org&gt;\n&quot;<br>&quot;Plural-Forms: nplurals=2; plural=(n &gt; 1);\n&quot;<br>&quot;MIME-Version: 1.0\n&quot;<br>&quot;Content-Type: text/plain; charset=utf-8\n&quot;<br>&quot;Content-Transfer-Encoding: 8bit\n&quot;<br>&quot;Generated-By: Babel 2.14.0\n&quot;<br><br>#: main.py:19<br>msgid &quot;Hello, this is a message in your language!&quot;<br>msgstr &quot;Bonjour, ceci est un message dans votre langue!&quot;</pre><p>Then compile the .po files into .mo files. This will compile translation catalogs into binary MO files.</p><pre>pybabel compile -d translations</pre><h4><strong>And voila!</strong> 🎉</h4><h3>See it in Action</h3><p>Now, you can use the Accept-Language header to choose the language of your API response. Run the FastAPI app and use cURL to send requests with different Accept-Language headers.</p><h4>English 🏴󠁧󠁢󠁥󠁮󠁧󠁿 🇺🇸</h4><pre>~$ curl -X &#39;GET&#39;   &#39;http://127.0.0.1:8000/greetings&#39; \<br>-H &#39;Accept-Language: en&#39;</pre><pre>{&quot;message&quot;:&quot;Hello, this is a message in your language!&quot;}</pre><h4>German 🇩🇪</h4><pre>~$ curl -X &#39;GET&#39;   &#39;http://127.0.0.1:8000/greetings&#39; \<br>-H &#39;Accept-Language: de&#39;</pre><pre>{&quot;message&quot;:&quot;Hallo, dies ist eine Nachricht in Ihrer Sprache!&quot;}</pre><h4>French 🇫🇷</h4><pre>~$ curl -X &#39;GET&#39;   &#39;http://127.0.0.1:8000/greetings&#39; \<br>-H &#39;Accept-Language: fr&#39;</pre><pre>{&quot;message&quot;:&quot;Bonjour, ceci est un message dans votre langue!&quot;}</pre><h3>Conclusion</h3><p>Internationalizing your FastAPI application makes it more accessible and user-friendly for a global audience.</p><p>Following these steps, you can easily support multiple languages, enhancing the user experience and broadening your application’s reach.</p><p>Implementing i18n ensures that your API can respond in the user’s preferred language, making your service more inclusive and adaptable to diverse user needs.</p><h3>Read More 📜</h3><ul><li><a href="https://medium.com/@amirm.lavasani/how-to-structure-your-fastapi-projects-0219a6600a8f">How to Structure Your FastAPI Projects</a></li><li><a href="https://medium.com/@amirm.lavasani/how-to-setup-a-fastapi-project-using-conda-and-poetry-aa98e007c7af">How to Setup a FastAPI Project using Conda and Poetry</a></li><li><a href="https://medium.com/@amirm.lavasani/how-to-add-automatic-versioning-to-your-fastapi-service-b008ed5f3edc">How to Setup Automatic Versioning for your FastAPI App</a></li></ul><h3>Resources</h3><ul><li><a href="https://babel.pocoo.org/en/stable/cmdline.html">Command-Line Interface - Babel 2.14.0 documentation</a></li><li><a href="https://docs.python.org/3/library/gettext.html">gettext - Multilingual internationalization services</a></li><li><a href="https://fastapi.tiangolo.com/tutorial/middleware/?h=middlewa">Middleware - FastAPI</a></li></ul><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=b546f7d183bb" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[How to Setup Automatic Versioning for your FastAPI App]]></title>
            <link>https://medium.com/@amirm.lavasani/how-to-add-automatic-versioning-to-your-fastapi-service-b008ed5f3edc?source=rss-2e98894ce1bf------2</link>
            <guid isPermaLink="false">https://medium.com/p/b008ed5f3edc</guid>
            <category><![CDATA[semantic-versioning]]></category>
            <category><![CDATA[software-development]]></category>
            <category><![CDATA[fastapi]]></category>
            <category><![CDATA[version-control]]></category>
            <category><![CDATA[python]]></category>
            <dc:creator><![CDATA[Amir Lavasani]]></dc:creator>
            <pubDate>Sun, 16 Jun 2024 08:56:08 GMT</pubDate>
            <atom:updated>2024-06-16T18:45:51.484Z</atom:updated>
            <content:encoded><![CDATA[<h4>FASTAPI FOUNDATION SERIES</h4><h4>Part 3: Versioning</h4><p>In this part, I explain why versioning is crucial for FastAPI applications and how to automate it with semantic versioning, Git commit messages, and the python-semantic-release package.</p><p>By the end, you’ll have an automatic versioning system for your FastAPI projects.</p><h3>How Does Versioning Help Us?</h3><ol><li><strong>Avoid Confusion:</strong> <em>Versioning helps keep track of changes and avoids confusion about which version is being used.</em></li><li><strong>Maintain Compatibility:</strong> <em>Ensures new updates work with older versions, preventing issues for users.</em></li><li><strong>Easier Debugging:</strong> <em>Knowing the exact version makes it easier to identify and fix bugs.</em></li><li><strong>Clear Communication:</strong> <em>Clearly communicates what changes have been made to other developers and users.</em></li><li><strong>Smooth Updates:</strong> <em>Facilitates smooth and predictable updates without breaking the application.</em></li></ol><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*4bEeF5noTjsA4gRCPeeS_Q.jpeg" /><figcaption>Dall-E generated image with the following concept: Two abstract sides: the left side shows tangled strings representing chaos, and the right side shows a single, straight string representing clarity.</figcaption></figure><h3>Understanding Semantic Versioning</h3><p>Semantic Versioning (<a href="https://semver.org/">SemVer</a>) is the most famous versioning standard. it uses a three-part version number: MAJOR.MINOR.PATCH.</p><ol><li><strong>MAJOR</strong> version increments when you make incompatible API changes.</li><li><strong>MINOR</strong> version increments when you add functionality in a backward-compatible manner.</li><li><strong>PATCH</strong> version increments when you make backward-compatible bug fixes.</li></ol><p>To learn more about SemVer read the following article or refer to the <a href="https://semver.org/">original docs</a>.</p><p><a href="https://medium.com/@amirm.lavasani/software-upgrade-versioning-semantic-versioning-4359cab321d4">Software Upgrade Versioning: Semantic Versioning</a></p><h3>Setting Up Automatic Version Bumping</h3><p>There are a couple of versioning packages out there. <a href="https://github.com/semantic-release/semantic-release">semantic-release</a> is one of the most famous and popular tools for versioning in the Javascript community.</p><p>We are going to use thepython-semantic-release which is the Python implementation of semantic-releasepackage.</p><p>We Integrate it with out FastAPI project using the <strong>three simple steps</strong>:</p><h4>1. Install python-semantic-release</h4><p>first, install python-semantic-release in your environment.</p><p>Use poetry to add python-semantic-release to dev dependencies or the default pip in your activated environment.</p><pre>(proj-env) user@host:~$ poerty add -G dev python-semantic-release</pre><pre>(proj-env) user@host:~$ pip install python-semantic-release</pre><h4>2. Generate Configuration</h4><p>Generate the configuration for your project and append it to the pyproject.toml using the following command.</p><pre>semantic-release generate-config --pyproject &gt;&gt; pyproject.toml</pre><p>Here is the default config that semantic-release generates:</p><pre>[tool.semantic_release]<br>assets = []<br>build_command_env = []<br>commit_message = &quot;{version}\n\nAutomatically generated by python-semantic-release&quot;<br>commit_parser = &quot;angular&quot;<br>logging_use_named_masks = false<br>major_on_zero = true<br>allow_zero_version = true<br>no_git_verify = false<br>tag_format = &quot;v{version}&quot;<br>version_variables = [&quot;src/app/version.py:__version__&quot;] # we added this<br><br>[tool.semantic_release.branches.main]<br>match = &quot;(main|master)&quot;<br>prerelease_token = &quot;rc&quot;<br>prerelease = false<br><br>[tool.semantic_release.changelog]<br>template_dir = &quot;templates&quot;<br>changelog_file = &quot;CHANGELOG.md&quot;<br>exclude_commit_patterns = []<br><br>[tool.semantic_release.changelog.environment]<br>block_start_string = &quot;{%&quot;<br>block_end_string = &quot;%}&quot;<br>variable_start_string = &quot;{{&quot;<br>variable_end_string = &quot;}}&quot;<br>comment_start_string = &quot;{#&quot;<br>comment_end_string = &quot;#}&quot;<br>trim_blocks = false<br>lstrip_blocks = false<br>newline_sequence = &quot;\n&quot;<br>keep_trailing_newline = false<br>extensions = []<br>autoescape = true<br><br>[tool.semantic_release.commit_author]<br>env = &quot;GIT_COMMIT_AUTHOR&quot;<br>default = &quot;semantic-release &lt;semantic-release&gt;&quot;<br><br>[tool.semantic_release.commit_parser_options]<br>allowed_tags = [&quot;build&quot;, &quot;chore&quot;, &quot;ci&quot;, &quot;docs&quot;, &quot;feat&quot;, &quot;fix&quot;, &quot;perf&quot;, &quot;style&quot;, &quot;refactor&quot;, &quot;test&quot;]<br>minor_tags = [&quot;feat&quot;]<br>patch_tags = [&quot;fix&quot;, &quot;perf&quot;]<br>default_bump_level = 0<br><br>[tool.semantic_release.remote]<br>name = &quot;origin&quot;<br>type = &quot;github&quot;<br>ignore_token_for_push = false<br>insecure = false<br><br>[tool.semantic_release.publish]<br>dist_glob_patterns = [&quot;dist/*&quot;]<br>upload_to_vcs_release = true</pre><h4>3. Add the Version File</h4><p>Create a Python file to store your version information. Place it in the root folder of your source:</p><pre># /src/app/version.py<br><br>&quot;&quot;&quot;<br>Version Information<br><br>This module provides the code version and is <br>automatically updated by the python-semantic-release package.<br><br>DO NOT EDIT IT MANUALLY.<br>&quot;&quot;&quot;<br><br>__version__ = 0.1.0</pre><p>Next, update your pyproject.toml to let semantic-release know how to use this file:</p><pre>[tool.semantic_release]<br># ... other configs<br>version_variables = [&quot;src/app/version.py:__version__&quot;]</pre><p><strong>And voila!</strong> 🎉</p><p>Now you can automatically bump your version using the format of your <strong>Git Commit Messages</strong>.</p><h3>Automatic Versioning Using Git Commit Messages</h3><p>python-semantic-release rely on commit messages to detect how to bump to the next version. This ensures versioning is consistent and based on the type of changes made.</p><p>By default, it uses the <a href="https://github.com/angular/angular.js/blob/master/DEVELOPERS.md#commits">Angular style</a>.</p><p>Commit messages should follow a precise format to maintain readability and generate changelogs.</p><h4><strong>Commit Message Format</strong></h4><ul><li><strong>Header</strong>: Includes type, scope (optional), and subject.</li><li><strong>Body</strong>: Details about the change.</li><li><strong>Footer</strong>: Notes on breaking changes or issue references.</li></ul><pre>&lt;type&gt;(&lt;scope&gt;): &lt;subject&gt;<br>&lt;BLANK LINE&gt;<br>&lt;body&gt;<br>&lt;BLANK LINE&gt;<br>&lt;footer&gt;</pre><h4><strong>Types</strong></h4><p>Commit message types determine the next version of your app. For example, the feat type increases the <strong>MINOR</strong> version number, while the fix type increases the <strong>PATCH</strong> number. Here are the standard types:</p><ul><li>feat: New feature</li><li>fix: Bug fix</li><li>docs: Documentation changes</li><li>style: Code style changes</li><li>refactor: Code changes without fixing bugs or adding features</li><li>perf: Performance improvements</li><li>test: Testing changes</li><li>chore: Build process or auxiliary tool changes</li></ul><p>You can also define custom types in the allowed_tags list in your pyproject.toml file.</p><h3><strong>Let’s Version</strong></h3><p>Now, let’s see it in action. Add your changes and commit with the standard format:</p><pre>(proj-env) user@host:~$ git commit -m &quot;feat: add automatic versioning&quot;</pre><p>Using semantic-release, you can automatically bump your version based on your commit message. This dry-run command shows the next version without making any changes. Our next version is v0.2.0</p><pre>(proj-env) user@host:~$ semantic-release --noop version --print<br>🛡 You are running in no-operation mode, because the &#39;--noop&#39; flag <br>was supplied<br>0.2.0</pre><p>To create the next version, run:</p><pre>(proj-env) user@host:~$ semantic-release version<br>0.2.0<br>The next version is: 0.2.0! 🚀</pre><p>semantic-release will update the version file, commit the changes, tag the commit, and push everything to your remote server.</p><p>Now you can also add this version to your FastAPI app:</p><pre>from app.version import __version__<br><br>app = FastAPI(<br>    version=__version__,<br>)</pre><h3>Automate Using GitHub Actions</h3><p>You can also set up your CI/CD pipeline to use semantic-release for automatic versioning after each successful merge into the main branch.</p><h4><strong>Create the Workflow File</strong></h4><p>Save the following YAML configuration as .github/workflows/version-bump.yml in your repository.</p><pre>name: Bump Version<br><br>on:<br>  push:<br>    branches:<br>      - main<br><br>jobs:<br>  bump-version:<br>    runs-on: ubuntu-latest<br>    <br>    permissions:<br>        actions: write<br>        contents: write<br>  <br>    steps:<br>      - name: Checkout repository<br>        uses: actions/checkout@v3<br>        with:<br>            fetch-depth: 0<br>      <br>      - name: Bump version using semantic-release<br>        uses: python-semantic-release/python-semantic-release@master<br>        with:<br>            github_token: ${{ secrets.GITHUB_TOKEN }}</pre><p>Now every time you push or merge other branches into the main branch, It will bump your code version depending on the commit messages, tag it, and make a release for that version in GitHub.</p><h3>Conclusion</h3><p>Versioning is essential for clarity and control in FastAPI projects. Automating it using semantic versioning, Git commit messages, and python-semantic-release improves clarity and maintainability.</p><p>By following this guide, you&#39;ll have an efficient versioning system for your FastAPI applications, ensuring smooth updates, easier debugging, and clear communication with your team. Automate your versioning to keep your FastAPI projects organized and future-proof.</p><h3>Read More 📜</h3><ul><li><a href="https://medium.com/@amirm.lavasani/how-to-setup-a-fastapi-project-using-conda-and-poetry-aa98e007c7af">How to Setup a FastAPI Project using Conda and Poetry</a></li><li><a href="https://medium.com/@amirm.lavasani/how-to-structure-your-fastapi-projects-0219a6600a8f">How to Structure Your FastAPI Projects</a></li></ul><h3>Resources</h3><ul><li><a href="https://semver.org/">Semantic Versioning 2.0.0</a></li><li><a href="https://python-poetry.org/docs/">Introduction</a></li><li><a href="https://github.com/python-semantic-release/python-semantic-release">GitHub - python-semantic-release/python-semantic-release: Automatic semantic versioning for python projects</a></li><li><a href="https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions">Workflow syntax for GitHub Actions - GitHub Docs</a></li></ul><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=b008ed5f3edc" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[How to Setup a FastAPI Project using Conda and Poetry]]></title>
            <link>https://medium.com/@amirm.lavasani/how-to-setup-a-fastapi-project-using-conda-and-poetry-aa98e007c7af?source=rss-2e98894ce1bf------2</link>
            <guid isPermaLink="false">https://medium.com/p/aa98e007c7af</guid>
            <category><![CDATA[software-engineering]]></category>
            <category><![CDATA[backend]]></category>
            <category><![CDATA[microservices]]></category>
            <category><![CDATA[fastapi]]></category>
            <category><![CDATA[python]]></category>
            <dc:creator><![CDATA[Amir Lavasani]]></dc:creator>
            <pubDate>Sat, 25 May 2024 06:24:37 GMT</pubDate>
            <atom:updated>2024-06-15T10:11:37.453Z</atom:updated>
            <content:encoded><![CDATA[<h4>FASTAPI FOUNDATION SERIES</h4><h4>Part 2: Environment and Dependencies</h4><p>In this part, we’ll explore tools and approaches for two crucial parts of a robust project setup:</p><ol><li><strong>Dependency Management<em>:</em></strong><em> It’s about handling the libraries and versions needed for your project to function correctly.</em></li><li><strong>Environment Configuration:</strong> <em>This involves setting up the environment where your project runs, and managing things like Python versions and system dependencies.</em></li></ol><p>Let’s go over each one quickly.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*mtZrvlgSD-f0DxYtohmcFA.jpeg" /><figcaption>Dall-E generated image with the following concept: A Digital Garden where plants symbolize project stages, with roots and branches as dependencies</figcaption></figure><h3>Dependency Management Approaches</h3><p>Dependency management is the process of ensuring that the required libraries and versions are handled correctly for the project to work.</p><p>There are two main approaches.</p><p>Using old-fashioned requirements.txt or using the more modern pyproject.toml .</p><h4><strong>Traditional Approach:</strong> <strong>requirements.txt</strong></h4><p>This approach has been tried and tested, offering a straightforward way to list project dependencies.</p><p>However, it has limitations like not separating different types of dependencies (such as development and test dependencies) and struggling with complex dependency constraints.</p><p>Another shortcoming is that you have to manually check and update the file to include new dependencies and their versions.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/660/1*HwT0WSigyzCOUYOuy678xw.png" /><figcaption>Sample of the requirements.txt file</figcaption></figure><h4>Modern Approach: pyproject.toml</h4><p>The pyproject.toml file serves as a central configuration hub for project-related tools.</p><p>It simplifies setup by consolidating all project configurations into one file. This includes building systems, package metadata, dependencies, and tool configurations like testing and linting settings.</p><p>Pyproject.toml offers several advantages over requirements.txt. It allows for a comprehensive specification of dependencies, including version constraints and metadata.</p><p>Additionally, it supports the separation of different dependency types, such as development and test dependencies, for better organization.</p><p>Also, tools like <strong>Poetry</strong> can automatically add and resolve dependencies and sub-dependencies versions, making management easier and ensuring compatibility with the latest library versions.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/660/1*TD90lOpTXpESvVHy4oiGqw.png" /><figcaption>Sample of the pyproject.toml file</figcaption></figure><p>For dependency management, we choose to use pyproject.toml approach with <strong>Poetry</strong>.</p><p><a href="https://packaging.python.org/en/latest/guides/writing-pyproject-toml/">Writing your pyproject.toml - Python Packaging User Guide</a></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*8kQprvAgwC-RJxxu7Eljbg.jpeg" /><figcaption>Dall-E generated image with the following concept: A Digital Garden where plants symbolize project stages, with roots and branches as dependencies</figcaption></figure><h3><strong>Environment Configuration</strong></h3><p>Environment management is crucial to ensure consistency and reproducibility across different systems.</p><p>By setting up a virtual environment, we isolate project dependencies from system dependencies, preventing conflicts and ensuring that the project runs smoothly regardless of the underlying system configuration.</p><p>Here are three main ways to manage virtual environments in Python.</p><ol><li><strong>Virtualenv:</strong> <em>Widely used for isolated Python environments, Virtualenv allows developers to manage project dependencies separately from the system-wide Python installation.</em></li><li><strong>Pyenv:</strong> <em>This tool enables users to manage multiple Python versions on one system, offering flexibility for switching between versions based on project needs.</em></li><li><strong>Conda:</strong> <em>Conda stands out as a powerful environment and package management tool that supports multiple programming languages. It not only creates isolated environments but also simplifies the installation of both Python and non-Python packages, making it an ideal choice for projects with complex dependencies.</em></li></ol><p>We choose <strong>Conda</strong> for its versatility and ease of use.</p><h3>Project Setup</h3><p>We choose <strong>Poetry</strong> for our dependency management and <strong>Conda</strong> for our virtual environment.</p><blockquote>Note that Poetry can also handle virtual environments using virtualenv. however it might not be its strong suit.</blockquote><h4>Install Conda and Poetry</h4><p>First, install <a href="https://docs.conda.io/projects/conda/en/latest/user-guide/install/linux.html">Conda</a> and <a href="https://python-poetry.org/docs/#installation">Poetry</a> on your system.</p><p>Install Conda on Ubuntu. Refer to the Miniconda <a href="https://docs.anaconda.com/free/miniconda/">documentation</a> for more details.</p><pre>mkdir -p ~/miniconda3<br>wget https://repo.anaconda.com/miniconda/Miniconda3-latest-Linux-x86_64.sh -O ~/miniconda3/miniconda.sh<br>bash ~/miniconda3/miniconda.sh -b -u -p ~/miniconda3<br>rm -rf ~/miniconda3/miniconda.sh</pre><p>Install Poetry on Ubuntu. Use the preferred pipx method. Refer to Poetry <a href="https://python-poetry.org/docs/">documentation</a> for more details.</p><pre>pipx install poetry</pre><blockquote>As Poetry documents point out multiple time, do not install Poetry in your project enviornment. Instead install it using pipx that handles Poetry’s own dependencies in isolation from your project.</blockquote><h4>Create Conda Environment</h4><p>Create your Conda environment and activate it. You can specify the Python version you like for your project.</p><pre>conda create --name proj-env python=3.11<br>conda activate proj-env</pre><h4>Setup Poetry</h4><p>Set up the Poetry project in the activated environment.</p><p>Poetry will detect that it is being created in an environment and use the activated environment.</p><pre>(proj-env) user@host:~$ poetry new poetry-conda-demo</pre><p>This command will create a project in the poetry-conda-demo folder and set up the minimal following file structure.</p><pre>.<br>├── poetry_conda_demo<br>│   └── __init__.py<br>├── pyproject.toml<br>├── README.md<br>└── tests<br>    └── __init__.py</pre><p>And here is the pyproject.toml for our project.</p><pre>[tool.poetry]<br>name = &quot;poetry-conda-demo&quot;<br>version = &quot;0.1.0&quot;<br>description = &quot;&quot;<br>authors = [&quot;Amir Lavasani &lt;amirm.lavasani@gmail.com&gt;&quot;]<br>readme = &quot;README.md&quot;<br><br>[tool.poetry.dependencies]<br>python = &quot;^3.10&quot;<br><br><br>[build-system]<br>requires = [&quot;poetry-core&quot;]<br>build-backend = &quot;poetry.core.masonry.api&quot;</pre><p>Now we can manage our dependencies using Poetry commands. Adding FastAPI to the project is as simple as this.</p><pre>(proj-env) user@host:~$ poetry add fastapi</pre><p>Poetry will install fastapi and all its sub-dependencies in the activated porj-env environment.</p><p>It will also automatically update the dependencies section of pyproject.toml .</p><p>It also creates a poetry.lock file. The poetry.lock file records the exact versions of dependencies and their sub-dependencies that are installed, ensuring consistent and reproducible environments across different systems.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/514/1*F8M59rze89mivgH0AN5lTw.png" /><figcaption>fastapi will be added automatically to pyproject.toml dependencies.</figcaption></figure><h3>Finally</h3><p>In this article, we explored the essential steps for setting up a robust FastAPI backend. We started by reviewing different methods for dependency management, highlighting the pros and cons of each.</p><p>We selected pyproject.toml with Poetry for its comprehensive features and ease of use.</p><p>Next, we examined popular environment management tools, ultimately choosing Conda for its versatility and simplicity.</p><p>Finally, we provided a step-by-step guide to setting up the project, including installing Conda and Poetry, and creating a project using these best practices.</p><p>By following these guidelines, you can ensure a well-organized and maintainable FastAPI backend setup.</p><h3>Read More 📜</h3><p><a href="https://medium.com/@amirm.lavasani/how-to-structure-your-fastapi-projects-0219a6600a8f">How to Structure Your FastAPI Projects</a></p><h3>Resources</h3><ul><li><a href="https://python-poetry.org/docs/">Introduction</a></li><li><a href="https://docs.anaconda.com/free/miniconda/">Miniconda - Anaconda documentation</a></li></ul><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=aa98e007c7af" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[How to Structure Your FastAPI Projects]]></title>
            <link>https://medium.com/@amirm.lavasani/how-to-structure-your-fastapi-projects-0219a6600a8f?source=rss-2e98894ce1bf------2</link>
            <guid isPermaLink="false">https://medium.com/p/0219a6600a8f</guid>
            <category><![CDATA[software-development]]></category>
            <category><![CDATA[python]]></category>
            <category><![CDATA[fastapi]]></category>
            <category><![CDATA[backend]]></category>
            <category><![CDATA[software-architecture]]></category>
            <dc:creator><![CDATA[Amir Lavasani]]></dc:creator>
            <pubDate>Tue, 14 May 2024 06:49:20 GMT</pubDate>
            <atom:updated>2024-05-14T06:49:20.798Z</atom:updated>
            <content:encoded><![CDATA[<h4>FastAPI FOUNDATION</h4><h4>Part 1: Blueprint</h4><p>In this article, we will discuss two main strategies for structuring your FastAPI projects and highlight the scenarios in which each one is more suitable.</p><h3>Why Proper Structuring Matters?</h3><p>Here are the most important reasons to structure your code based on best practices.</p><ol><li><strong>Enhanced Scalability:</strong> <em>Well-organized code grows smoothly with your FastAPI project.</em></li><li><strong>Improved Maintainability:</strong> <em>Easy-to-understand code makes updates and fixes simple.</em></li><li><strong>Streamlined Collaboration:</strong> <em>Clear structure helps teams work together efficiently.</em></li></ol><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*YTwsSdvhdRsjbGp3OKSG4A.jpeg" /><figcaption>Dall-E generated image with the following concept: An abstract software blueprint</figcaption></figure><h3>Key Principles for Structuring Projects</h3><p>In building FastAPI applications, it’s crucial to follow these best practices:</p><ol><li><strong>Separation of Concerns:</strong> <em>Separate different aspects of your FastAPI project, such as routes, models, and business logic, for clarity and maintainability.</em></li><li><strong>Modularization:</strong> <em>Break down your FastAPI application into reusable modules to promote code reusability and organization.</em></li><li><strong>Dependency Injection:</strong> <em>Decouple components by implementing dependency injection, which allows for more flexible and testable code in FastAPI using libraries like </em>fastapi.Dependencies<em>.</em></li><li><strong>Testability:</strong> <em>Prioritize writing testable code in FastAPI applications by employing strategies like dependency injection and mocking to ensure robust testing and quality assurance.</em></li></ol><h3>Structuring Formats</h3><p>FastAPI applications can be structured in different ways to accommodate various project needs.</p><p>There are two main approaches for structuring projects. One is based on file type and the other is based on module functionality.</p><h3>1. Structuring based on File-Type</h3><p>In this approach, files are organized by type (e.g., API, CRUD, models, schemas, routers) as represented by <a href="https://fastapi.tiangolo.com/tutorial/bigger-applications/">FastAPI itself</a>.</p><p>This structure is more suitable for microservices or projects with fewer scopes:</p><pre>.<br>├── app  # Contains the main application files.<br>│   ├── __init__.py   # this file makes &quot;app&quot; a &quot;Python package&quot;<br>│   ├── main.py       # Initializes the FastAPI application.<br>│   ├── dependencies.py # Defines dependencies used by the routers<br>│   ├── routers<br>│   │   ├── __init__.py<br>│   │   ├── items.py  # Defines routes and endpoints related to items.<br>│   │   └── users.py  # Defines routes and endpoints related to users.<br>│   ├── crud<br>│   │   ├── __init__.py<br>│   │   ├── item.py  # Defines CRUD operations for items.<br>│   │   └── user.py  # Defines CRUD operations for users.<br>│   ├── schemas<br>│   │   ├── __init__.py<br>│   │   ├── item.py  # Defines schemas for items.<br>│   │   └── user.py  # Defines schemas for users.<br>│   ├── models<br>│   │   ├── __init__.py<br>│   │   ├── item.py  # Defines database models for items.<br>│   │   └── user.py  # Defines database models for users.<br>│   ├── external_services<br>│   │   ├── __init__.py<br>│   │   ├── email.py          # Defines functions for sending emails.<br>│   │   └── notification.py   # Defines functions for sending notifications<br>│   └── utils<br>│       ├── __init__.py<br>│       ├── authentication.py  # Defines functions for authentication.<br>│       └── validation.py      # Defines functions for validation.<br>├── tests<br>│   ├── __init__.py<br>│   ├── test_main.py<br>│   ├── test_items.py  # Tests for the items module.<br>│   └── test_users.py  # Tests for the users module.<br>├── requirements.txt<br>├── .gitignore<br>└── README.md</pre><h4><strong>In this structure</strong></h4><ul><li>app/: Contains the main application files.</li><li>main.py: Initializes the FastAPI application.</li><li>dependencies.py: Defines dependencies used by the routers.</li><li>routers/: Contains router modules.</li><li>crud/: Contains CRUD (Create, Read, Update, Delete) operation modules.</li><li>schemas/: Contains Pydantic schema modules.</li><li>models/: Contains database model modules.</li><li>external_services/: Contains modules for interacting with external services.</li><li>utils/: Contains utility modules.</li><li>tests/: Contains test modules.</li></ul><h3>2. Structuring based on Module-Functionality</h3><p>In the second approach, we organize our files based on package functionality for example authentication sub-package, users sub-package, and posts sub-package.</p><p>The module-functionality structure is better suited for monolithic projects containing numerous domains and modules. By grouping all file types required by a single sub-package, it improves development efficiency.</p><p>This structure is suggested by the <a href="https://github.com/zhanymkanov/fastapi-best-practices#1-project-structure-consistent--predictable">fastapi-best-practices</a> GitHub repository.</p><p>In this structure, Each package has its own router, schemas, models, etc.</p><pre>fastapi-project<br>├── alembic/<br>├── src<br>│   ├── auth<br>│   │   ├── router.py         # auth main router with all the endpoints<br>│   │   ├── schemas.py        # pydantic models<br>│   │   ├── models.py         # database models<br>│   │   ├── dependencies.py   # router dependencies<br>│   │   ├── config.py         # local configs<br>│   │   ├── constants.py      # module-specific constants<br>│   │   ├── exceptions.py     # module-specific errors<br>│   │   ├── service.py        # module-specific business logic<br>│   │   └── utils.py          # any other non-business logic functions<br>│   ├── aws<br>│   │   ├── client.py  # client model for external service communication<br>│   │   ├── schemas.py<br>│   │   ├── config.py<br>│   │   ├── constants.py<br>│   │   ├── exceptions.py<br>│   │   └── utils.py<br>│   └── posts<br>│   │   ├── router.py<br>│   │   ├── schemas.py<br>│   │   ├── models.py<br>│   │   ├── dependencies.py<br>│   │   ├── constants.py<br>│   │   ├── exceptions.py<br>│   │   ├── service.py<br>│   │   └── utils.py<br>│   ├── config.py      # global configs<br>│   ├── models.py      # global database models<br>│   ├── exceptions.py  # global exceptions<br>│   ├── pagination.py  # global module e.g. pagination<br>│   ├── database.py    # db connection related stuff<br>│   └── main.py<br>├── tests/<br>│   ├── auth<br>│   ├── aws<br>│   └── posts<br>├── templates/<br>│   └── index.html<br>├── requirements<br>│   ├── base.txt<br>│   ├── dev.txt<br>│   └── prod.txt<br>├── .env<br>├── .gitignore<br>├── logging.ini<br>└── alembic.ini</pre><h4><strong>In this structure</strong></h4><p>Store all domain directories inside src folder.</p><ol><li>src/: The highest level of an app, contains common models, configs, and constants, etc.</li><li>src/main.py: Root of the project, which inits the FastAPI app</li></ol><p>Each package has its own router, schemas, models, etc.</p><ol><li>router.py: is the core of each module with all the endpoints</li><li>schemas.py: for pydantic models</li><li>models.py: for database models</li><li>service.py: module-specific business logic</li><li>dependencies.py: router dependencies</li><li>constants.py: module-specific constants and error codes</li><li>config.py: e.g. env vars</li><li>utils.py: non-business logic functions, e.g. response normalization, data enrichment, etc.</li><li>exceptions.py: module-specific exceptions, e.g. PostNotFound, InvalidUserData</li></ol><p>When a package requires services or dependencies or constants from other packages, import them with an explicit module name to avoid ambiguity.</p><pre>from src.auth import constants as auth_constants<br>from src.notifications import service as notification_service<br>from src.posts.constants import ErrorCode as PostsErrorCode  # in case we have Standard ErrorCode in constants module of each package</pre><h3>Finally</h3><p>In conclusion, structuring your FastAPI projects is essential for maintaining scalability, readability, and maintainability as your application grows. By organizing your code effectively, you ensure that it remains manageable and adaptable to evolving requirements.</p><p>We discussed two main types of structuring FastAPI projects: the file-type structure and the module-functionality structure.</p><p>The file-type structure, represented by FastAPI itself, organizes files based on their type (e.g., routers, schemas, models). This structure is suitable for microservice architectures where individual services have single responsibilities.</p><p>On the other hand, the module-functionality structure separates files based on module functionality rather than file type. This approach is more suitable for larger monolithic applications, promoting better organization and maintainability.</p><p>In choosing the right structure for your FastAPI project, consider factors such as project size, complexity, and architectural design. Ultimately, whether you opt for the file-type structure or the module functionality structure, prioritizing organization and clarity will contribute to the long-term success of your FastAPI applications.</p><h4>Resources</h4><ul><li><a href="https://fastapi.tiangolo.com/tutorial/bigger-applications/">Bigger Applications - Multiple Files - FastAPI</a></li><li><a href="https://github.com/zhanymkanov/fastapi-best-practices#1-project-structure-consistent--predictable">GitHub - zhanymkanov/fastapi-best-practices: FastAPI Best Practices and Conventions we used at our startup</a></li></ul><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=0219a6600a8f" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Design Patterns in Python: Bridge]]></title>
            <link>https://medium.com/@amirm.lavasani/design-patterns-in-python-bridge-c34f3fcdd2eb?source=rss-2e98894ce1bf------2</link>
            <guid isPermaLink="false">https://medium.com/p/c34f3fcdd2eb</guid>
            <category><![CDATA[software-architecture]]></category>
            <category><![CDATA[programming]]></category>
            <category><![CDATA[design-patterns]]></category>
            <category><![CDATA[python]]></category>
            <category><![CDATA[bridge-pattern]]></category>
            <dc:creator><![CDATA[Amir Lavasani]]></dc:creator>
            <pubDate>Tue, 23 Apr 2024 05:49:42 GMT</pubDate>
            <atom:updated>2024-04-23T05:49:42.941Z</atom:updated>
            <content:encoded><![CDATA[<h4>TUTORIAL SERIES</h4><h4>Linking Abstraction and Implementation</h4><blockquote><em>Have you encountered recurring coding challenges? Imagine having a toolbox of tried-and-true solutions readily available. That’s precisely what design patterns provide. In </em><a href="https://medium.com/@amirm.lavasani/design-patterns-in-python-a-series-f502b7804ae5"><em>this series</em></a><em>, we’ll explore what these patterns are and how they can elevate your coding skills.</em></blockquote><p><a href="https://medium.com/@amirm.lavasani/design-patterns-in-python-a-series-f502b7804ae5">Design Patterns in Python: A Series</a></p><h3>Understanding the Bridge Pattern</h3><h4>What is the Bridge Design Pattern?</h4><p>The Bridge Design Pattern is a structural design pattern that decouples an abstraction from its implementation, allowing them to vary independently. It achieves this by providing a bridge between the abstraction and its implementation, enabling changes to one without affecting the other.</p><h4>When to Use the Bridge Pattern:</h4><p>When considering the use of the Bridge Design Pattern:</p><ol><li><strong>Divide and organize a monolithic class with multiple variants:</strong> <em>If a class handles various functionalities, such as working with different database servers, and you want to avoid a monolithic structure.</em></li><li><strong>Extend a class in orthogonal dimensions:</strong> <em>When you need to extend a class in multiple independent dimensions, the Bridge Pattern suggests creating separate class hierarchies for each dimension.</em></li><li><strong>Switch implementations at runtime:</strong> <em>If you need the flexibility to replace implementation objects within the abstraction dynamically, the Bridge Pattern allows for easy implementation swapping.</em></li></ol><h4>Practical Example: File Storage Abstraction</h4><p>This example demonstrates the Bridge Design Pattern by creating a file storage abstraction with implementations for local, cloud, and network storage.</p><p>It shows how the pattern separates storage abstraction from specific implementations for flexibility and maintenance.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*jF2txbRCzNFdvFow7DUDWA.jpeg" /><figcaption>Dall-E generated image with the following concept: A conceptual drawing of a bridge built from abstract shapes</figcaption></figure><h3>Abstraction and Implementation</h3><p>In the Bridge Design Pattern context, the terms Abstraction and Implementation refer to fundamental concepts that facilitate the separation of concerns and promote code maintainability.</p><ol><li><strong>Abstraction</strong> serves as the high-level control layer, delegating work to the Implementation layer. Abstraction, like a graphical user interface (GUI), interacts with the underlying operating system code (API).</li><li><strong>Implementation</strong>, or the platform, contains platform-specific code and is declared through a common interface. This allows interchangeable implementations linked to the abstraction object.</li></ol><p>By splitting classes into Abstraction and Implementation hierarchies, the Bridge pattern simplifies code maintenance and promotes flexibility.</p><p>In the above example, GUI changes won’t affect API-related classes, and adding support for new operating systems in API requires minimal modifications.</p><h3>Terminology and Key Components</h3><p>Here are the fundamental components involved:</p><ol><li><strong>Abstraction:</strong> <em>Provides high-level control logic and relies on the implementation object for low-level work.</em></li><li><strong>Implementation:</strong> <em>Declares the interface common to all concrete implementations, allowing communication with the abstraction through declared methods.</em></li><li><strong>Concrete Implementations:</strong> <em>Contain platform-specific code and provide implementations for the methods declared in the implementation interface.</em></li><li><strong>Refined Abstractions:</strong> <em>Variants of control logic that work with different implementations via the general implementation interface.</em></li><li><strong>Client:</strong> <em>Primarily interacts with the abstraction, responsible for linking the abstraction object with one of the implementation objects.</em></li></ol><p>Understanding how these components interact is crucial for effectively utilizing the Bridge Pattern in software design.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/560/1*GqwFD7lF9E39o5xLo3AB_w.png" /><figcaption>Bridge design pattern structure diagram. Image from <a href="https://refactoring.guru/design-patterns/bridge">refactoring.guru</a></figcaption></figure><h3>Bridge Implementation in Python</h3><h4>Step 1: Define Abstraction</h4><p>Abstract class representing the high-level control layer.</p><pre># Step 1: Define Abstraction (Abstract class)<br>class Abstraction(ABC):<br>    &quot;&quot;&quot;Abstract class representing the high-level control layer.&quot;&quot;&quot;<br>    <br>    def __init__(self, implementation):<br>        self._implementation = implementation<br><br>    @abstractmethod<br>    def perform_action(self):<br>        &quot;&quot;&quot;Perform an action using the implementation.&quot;&quot;&quot;<br>        pass</pre><h4>Step 2: Define Implementation</h4><p>Abstract class representing the platform-specific code.</p><pre># Step 2: Define Implementation (Abstract class)<br>class Implementation(ABC):<br>    &quot;&quot;&quot;Abstract class representing the platform-specific code.&quot;&quot;&quot;<br>    <br>    @abstractmethod<br>    def action_impl(self):<br>        &quot;&quot;&quot;Perform the actual action.&quot;&quot;&quot;<br>        pass</pre><h4>Step 3: Create Concrete Implementations</h4><p>Concrete implementation for platforms A and B.</p><pre># Step 3: Create Concrete Implementations<br>class ConcreteImplementationA(Implementation):<br>    &quot;&quot;&quot;Concrete implementation for platform A.&quot;&quot;&quot;<br>    <br>    def action_impl(self):<br>        return &quot;Action performed by Implementation A&quot;<br><br>class ConcreteImplementationB(Implementation):<br>    &quot;&quot;&quot;Concrete implementation for platform B.&quot;&quot;&quot;<br>    <br>    def action_impl(self):<br>        return &quot;Action performed by Implementation B&quot;</pre><h4>Step 4: Create Refined Abstractions</h4><p>Refined abstraction provides variants of control logic.</p><pre># Step 4: Create Refined Abstractions<br>class RefinedAbstraction(Abstraction):<br>    &quot;&quot;&quot;Refined abstraction providing variants of control logic.&quot;&quot;&quot;<br>    <br>    def perform_action(self):<br>        &quot;&quot;&quot;Perform an action using the implementation.&quot;&quot;&quot;<br>        return self._implementation.action_impl()</pre><h4>Main Client Code</h4><p>The main section showcases usage.</p><pre># Main section to showcase usage<br>if __name__ == &quot;__main__&quot;:<br>    # Create concrete implementations<br>    implementation_a = ConcreteImplementationA()<br>    implementation_b = ConcreteImplementationB()<br><br>    # Create refined abstractions and link them with concrete implementations<br>    refined_abstraction_a = RefinedAbstraction(implementation_a)<br>    refined_abstraction_b = RefinedAbstraction(implementation_b)<br><br>    # Use refined abstractions to perform actions<br>    print(refined_abstraction_a.perform_action())  # Output: Action performed by Implementation A<br>    print(refined_abstraction_b.perform_action())  # Output: Action performed by Implementation B</pre><h4>GitHub Repo 🎉</h4><p>Explore all code examples and design pattern implementations on GitHub!</p><p><a href="https://github.com/AmirLavasani/python-design-patterns">GitHub - AmirLavasani/python-design-patterns: Explore design patterns using Python with code examples to solve common software challenges.</a></p><h3>Practical Example: File Storage</h3><h4>Step 1: Define Abstraction</h4><p>Define an abstract class representing the file storage abstraction. This class will declare methods for saving files.</p><pre>from abc import ABC, abstractmethod<br><br># Step 1: Define Abstraction (Abstract class)<br>class FileStorage(ABC):<br>    &quot;&quot;&quot;Abstract class representing the file storage abstraction.&quot;&quot;&quot;<br>    <br>    @abstractmethod<br>    def save_file(self, file_name):<br>        &quot;&quot;&quot;Abstract method to save a file.&quot;&quot;&quot;<br>        pass</pre><h4>Step 2: Define Implementation</h4><p>Define an abstract class representing the storage implementation. This class will declare methods for saving files specific to each storage location.</p><pre># Step 2: Define Implementation (Abstract class)<br>class StorageImplementation(ABC):<br>    &quot;&quot;&quot;Abstract class representing the storage implementation.&quot;&quot;&quot;<br>    <br>    @abstractmethod<br>    def save(self, file_name):<br>        &quot;&quot;&quot;Abstract method to save a file.&quot;&quot;&quot;<br>        pass</pre><h4>Step 3: Create Concrete Implementations</h4><p>Implement concrete classes for local storage, cloud storage, and network storage. Each class will provide a specific implementation for saving files.</p><pre># Step 3: Create Concrete Implementations<br>class LocalStorage(StorageImplementation):<br>    &quot;&quot;&quot;Concrete implementation for local file storage.&quot;&quot;&quot;<br>    <br>    def save(self, file_name):<br>        &quot;&quot;&quot;Save a file locally.&quot;&quot;&quot;<br>        return f&quot;File &#39;{file_name}&#39; saved locally&quot;</pre><pre>class CloudStorage(StorageImplementation):<br>    &quot;&quot;&quot;Concrete implementation for cloud file storage.&quot;&quot;&quot;<br>    <br>    def save(self, file_name):<br>        &quot;&quot;&quot;Save a file to the cloud.&quot;&quot;&quot;<br>        return f&quot;File &#39;{file_name}&#39; saved to the cloud&quot;</pre><pre>class NetworkStorage(StorageImplementation):<br>    &quot;&quot;&quot;Concrete implementation for network file storage.&quot;&quot;&quot;<br>    <br>    def save(self, file_name):<br>        &quot;&quot;&quot;Save a file to a network location.&quot;&quot;&quot;<br>        return f&quot;File &#39;{file_name}&#39; saved to a network location&quot;</pre><h4>Step 4: Create Refined Abstractions</h4><p>Create a refined abstraction class that extends the file storage abstraction. This class will delegate file storage operations to the appropriate storage implementation based on runtime configurations.</p><pre># Step 4: Create Refined Abstraction<br>class AdvancedFileStorage(FileStorage):<br>    &quot;&quot;&quot;Refined abstraction for advanced file storage.&quot;&quot;&quot;<br>    <br>    def __init__(self, storage_impl):<br>        &quot;&quot;&quot;Initialize with a specific storage implementation.&quot;&quot;&quot;<br>        self._storage_impl = storage_impl<br>    <br>    def save_file(self, file_name):<br>        &quot;&quot;&quot;Save a file using the specified storage implementation.&quot;&quot;&quot;<br>        return self._storage_impl.save(file_name)</pre><h4>Main Client Code</h4><pre># Main section to showcase usage<br>if __name__ == &quot;__main__&quot;:<br>    # Create concrete implementations<br>    local_storage = LocalStorage()<br>    cloud_storage = CloudStorage()<br>    network_storage = NetworkStorage()<br><br>    # Create refined abstractions and link them with concrete implementations<br>    advanced_local_storage = AdvancedFileStorage(local_storage)<br>    advanced_cloud_storage = AdvancedFileStorage(cloud_storage)<br>    advanced_network_storage = AdvancedFileStorage(network_storage)<br><br>    # Use refined abstractions to save files<br>    print(advanced_local_storage.save_file(&quot;example.txt&quot;))    # Output: File &#39;example.txt&#39; saved locally<br>    print(advanced_cloud_storage.save_file(&quot;example.txt&quot;))    # Output: File &#39;example.txt&#39; saved to the cloud<br>    print(advanced_network_storage.save_file(&quot;example.txt&quot;))  # Output: File &#39;example.txt&#39; saved to a network location</pre><h3>Real-World Use Cases for Bridge</h3><ol><li><strong>Python’s Tkinter and PyQT:</strong> <em>Similar to Java GUI frameworks, Python’s GUI libraries employ the Bridge pattern to separate the GUI components from platform-specific details.</em></li><li><strong>OpenGL and DirectX:</strong> <em>Graphics rendering libraries like OpenGL and DirectX utilize the Bridge pattern to abstract away hardware-specific implementations, allowing developers to create cross-platform graphics applications.</em></li><li><strong>jQuery:<em> </em></strong><em>The jQuery JavaScript library employs the Bridge pattern to abstract away browser differences and provide a consistent API for DOM manipulation and event handling across different web browsers.</em></li><li><strong>TensorFlow and PyTorch:</strong> <em>Deep learning frameworks like TensorFlow and PyTorch use the Bridge pattern to separate the high-level neural network abstraction from specific hardware accelerators and optimization techniques, enabling scalable and efficient deep learning computations.</em></li><li><strong>Quartz Scheduler:</strong> <em>The Quartz Scheduler library utilizes the Bridge pattern to decouple the scheduling logic from specific job store implementations, allowing developers to store job data in various databases or other storage systems.</em></li></ol><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*T8PwEz8Se8-pxzZZrcfnjA.jpeg" /><figcaption>Dall-E generated image with the following concept: A conceptual drawing of a bridge built from abstract shapes</figcaption></figure><h3>Bridge Pors and Cons</h3><p>When working with the Bridge Design Pattern, it’s essential to understand its advantages and potential drawbacks:</p><h4>Pros</h4><ol><li><strong>Platform Independence:</strong> <em>Bridge allows the creation of platform-independent classes and applications, enhancing portability.</em></li><li><strong>Abstraction:</strong> <em>Client code interacts with high-level abstractions, shielding it from platform-specific details, thus promoting clarity.</em></li><li><strong>Open/Closed Principle:</strong> <em>Bridge supports the principle of open/closed, enabling the introduction of new abstractions and implementations independently.</em></li><li><strong>Single Responsibility Principle:</strong> <em>Bridge encourages separation of concerns, allowing focus on high-level logic in abstractions and platform details in implementations.</em></li></ol><h4>Cons</h4><p><strong>Increased Complexity:</strong> Overuse of the pattern in highly cohesive classes can lead to code complexity, making it harder to understand and maintain.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*4xyh7dqRFU09zVLUueYJ2g.jpeg" /><figcaption>Dall-E generated image with the following concept: Two circles representing abstraction and implementation, linked by a bridge</figcaption></figure><h3>Bridge’s Relations with Other Patterns</h3><p>When looking at the Bridge Design Pattern, it’s important to know how it connects with other patterns.</p><h4>Bridge vs. Adapter:</h4><p><strong>Bridge</strong> is typically designed up-front, allowing the development of parts of an application independently.</p><p>Conversely, the <strong>Adapter</strong> is commonly used with existing applications to reconcile otherwise-incompatible classes.</p><h4>Bridge, State, Strategy, and Adapter:</h4><p>These patterns share <strong>similar structures</strong>, based on composition and delegating work to other objects.</p><p>However, they address distinct problems and communicate different solutions to developers.</p><h4>Bridge with Abstract Factory:</h4><p>Abstract Factory complements Bridge when specific abstractions defined by Bridge require particular implementations.</p><p>Abstract Factory encapsulates these relationships, simplifying the complexity of client code.</p><h4>Bridge with Builder:</h4><p>Builder can be combined with Bridge, where the director class acts as the abstraction and different builders serve as implementations.</p><p>This combination allows for the creation of complex objects while maintaining the separation of concerns.</p><h3>Conclusion</h3><p>In conclusion, we’ve delved into the Bridge Pattern in Python, discovering its ability to separate abstraction from implementation, offering flexibility and maintenance advantages.</p><p>We’ve explored its key components, pros and cons, and compared it to related patterns. Additionally, we implemented a practical file storage system showcasing the pattern’s power.</p><p>Keep coding and exploring new design patterns! 👩‍💻</p><h3>Next on the Series 🚀</h3><p><a href="https://medium.com/@amirm.lavasani/design-patterns-in-python-flyweight-e7a7334f82b1">Design Patterns in Python: Flyweight</a></p><h3>Read More 📜</h3><ul><li><a href="https://medium.com/@amirm.lavasani/design-patterns-in-python-template-method-1b76fb561c4a">Design Patterns in Python: Template Method</a></li><li><a href="https://medium.com/@amirm.lavasani/design-patterns-in-python-visitor-f20085b35d8b">Design Patterns in Python: Visitor</a></li></ul><h3>The Series 🧭</h3><p><a href="https://medium.com/@amirm.lavasani/design-patterns-in-python-a-series-f502b7804ae5">Design Patterns in Python: A Series</a></p><h4>Explore the GitHub Repo 🎉</h4><p><a href="https://github.com/AmirLavasani/python-design-patterns">GitHub - AmirLavasani/python-design-patterns: Explore design patterns using Python with code examples to solve common software challenges.</a></p><h4>References</h4><ol><li><a href="https://www.goodreads.com/en/book/show/85009">Design Patterns: Elements of Reusable Object-Oriented Software</a> (Book)</li><li><a href="https://refactoring.guru/design-patterns/bridge">refactoring.guru Bridge</a></li><li><a href="https://www.goodreads.com/en/book/show/58128">Head First Design Patterns</a> (Book)</li><li><a href="https://en.wikipedia.org/wiki/Bridge_pattern">Wikipedia Bridge Pattern</a></li><li><a href="https://sourcemaking.com/design_patterns/bridge">Sourcemaking Bridge Design Pattern</a></li><li><a href="https://www.pentalog.com/blog/design-patterns/bridge-design-patterns/">Bridge Design Pattern — A different kind of Golden Gate</a></li></ol><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=c34f3fcdd2eb" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Design Patterns in Python: Flyweight]]></title>
            <link>https://medium.com/@amirm.lavasani/design-patterns-in-python-flyweight-e7a7334f82b1?source=rss-2e98894ce1bf------2</link>
            <guid isPermaLink="false">https://medium.com/p/e7a7334f82b1</guid>
            <category><![CDATA[software-architecture]]></category>
            <category><![CDATA[python]]></category>
            <category><![CDATA[flyweight-pattern]]></category>
            <category><![CDATA[programming]]></category>
            <category><![CDATA[design-patterns]]></category>
            <dc:creator><![CDATA[Amir Lavasani]]></dc:creator>
            <pubDate>Mon, 15 Apr 2024 10:32:55 GMT</pubDate>
            <atom:updated>2024-04-15T10:32:55.341Z</atom:updated>
            <content:encoded><![CDATA[<h4>TUTORIAL SERIES</h4><h4>Optimizing Memory Usage</h4><blockquote><em>Have you encountered recurring coding challenges? Imagine having a toolbox of tried-and-true solutions readily available. That’s precisely what design patterns provide. In </em><a href="https://medium.com/@amirm.lavasani/design-patterns-in-python-a-series-f502b7804ae5"><em>this series</em></a><em>, we’ll explore what these patterns are and how they can elevate your coding skills.</em></blockquote><p><a href="https://medium.com/@amirm.lavasani/design-patterns-in-python-a-series-f502b7804ae5">Design Patterns in Python: A Series</a></p><h3>Understanding the Flyweight Pattern</h3><h4>What is the Flyweight Design Pattern?</h4><p>The Flyweight Design Pattern is categorized under structural design patterns and is commonly used to manage objects that share similar or identical states.</p><p>The key idea behind the Flyweight pattern is to separate the intrinsic state (shared among multiple objects) from the extrinsic state (unique to each object).</p><p>By doing so, we can store the intrinsic state in a centralized location and share it among multiple objects, while the extrinsic state can be managed individually by each object.</p><h4>Intrinsic vs. Extrinsic State</h4><ol><li><strong>Intrinsic State:</strong> This refers to constant data stored within an object, residing solely within the object itself and immutable by external entities. It remains consistent across different contexts and is shared among multiple objects.</li><li><strong>Extrinsic State:</strong> Conversely, the extrinsic state represents the variable data of an object, influenced or altered by external factors or objects. This state is dynamic and can vary between different instances of the same object.</li></ol><p>The Flyweight pattern suggests separating extrinsic state from objects, preserving the intrinsic state for reuse across contexts. This minimizes object instances, as they mainly differ in intrinsic state, simplifying the system.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*wwCXuc0NcvylYfflutewPA.jpeg" /><figcaption>Dall-E generated image with the following concept: A large central node with cords extending outward to smaller nodes surrounding it, symbolizing shared resources distributed from a central source.</figcaption></figure><h4>When to Use the Flyweight Pattern:</h4><p>The Flyweight Pattern is suitable for the following scenarios:</p><ol><li><strong>Large Number of Objects:</strong> <em>When your application needs to create a large number of objects with shared intrinsic state.</em></li><li><strong>Memory Optimization:</strong> <em>If memory optimization is a concern and you want to reduce the memory footprint by sharing common state among multiple objects.</em></li><li><strong>Immutable State:</strong> <em>When the objects can be made immutable or the shared state can be safely shared among multiple instances without risk of modification.</em></li><li><strong>Performance Improvement:</strong> <em>If performance improvement is desired by minimizing object creation and reducing redundant data storage.</em></li><li><strong>Extrinsic State Separation:</strong> <em>When it’s feasible to separate the intrinsic state (shared among objects) from the extrinsic state (unique to each object) to optimize memory usage.</em></li></ol><h4>Practical Example: Game Enemy Character</h4><p>We use the Flyweight pattern to optimize the management of game enemy characters. We define a Flyweight class for shared intrinsic data, create Concrete Flyweight classes for specific enemy types, and implement a Flyweight Factory for object management.</p><p>By separating intrinsic and extrinsic data, we optimize memory usage while allowing for individual customization during gameplay. This approach efficiently handles large numbers of characters, enhancing performance and scalability in game development.</p><h3>Terminology and Key Components</h3><p>Understanding the key components of the Flyweight pattern is essential for its effective implementation. Here are the crucial components involved:</p><ol><li><strong>Flyweight:</strong> <em>Contains the intrinsic state shared between multiple objects, with the same flyweight object usable in various contexts. It stores the intrinsic state and receives the extrinsic state from the context.</em></li><li><strong>Context:</strong> <em>Holds the extrinsic state unique across all original objects. When paired with a flyweight object, it represents the full state of the original object.</em></li><li><strong>Client:</strong> <em>Calculates or stores the extrinsic state of flyweights. It treats flyweights as template objects and configures them at runtime by passing contextual data into their methods.</em></li><li><strong>Flyweight Factory:</strong> <em>Manages a pool of existing flyweights, handling their creation and reuse. Clients interact with the factory to obtain flyweight instances, passing intrinsic state for retrieval or creation.</em></li></ol><figure><img alt="" src="https://cdn-images-1.medium.com/max/640/1*gPtDjj9MM6_OYuD0EMULlw.png" /><figcaption>Flyweight design pattern structure diagram. Image from <a href="https://refactoring.guru/design-patterns/flyweight">refactoring.guru</a></figcaption></figure><h3>Flyweight Implementation in Python</h3><p>This implementation demonstrates the abstract version of the Flyweight design pattern, including the Flyweight interface, concrete flyweight classes, flyweight factory, and client class.</p><h4>Step 1: Define the Flyweight interface</h4><p>Define the Flyweight interface with an operation method.</p><pre>from abc import ABC, abstractmethod<br><br># Step 1: Define the Flyweight interface<br>class Flyweight(ABC):<br>    &quot;&quot;&quot;<br>    The Flyweight interface declares a method for accepting extrinsic state<br>    and performing operations based on it.<br>    &quot;&quot;&quot;<br><br>    @abstractmethod<br>    def operation(self, extrinsic_state):<br>        &quot;&quot;&quot;<br>        Operation method accepting extrinsic state as input.<br>        &quot;&quot;&quot;<br>        pass</pre><h4>Step 2: Create concrete flyweight classes</h4><p>Create concrete flyweight classes implementing the interface and storing intrinsic state.</p><pre># Step 2: Create concrete flyweight classes<br>class ConcreteFlyweight(Flyweight):<br>    &quot;&quot;&quot;<br>    ConcreteFlyweight implements the Flyweight interface and stores intrinsic state.<br>    &quot;&quot;&quot;<br><br>    def __init__(self, intrinsic_state):<br>        self._intrinsic_state = intrinsic_state<br><br>    def operation(self, extrinsic_state):<br>        return f&quot;ConcreteFlyweight: Intrinsic State - {self._intrinsic_state}, Extrinsic State - {extrinsic_state}&quot;</pre><h4>Step 3: Implement the Flyweight Factory</h4><p>Implement a Flyweight Factory to manage flyweight objects and ensure their uniqueness.</p><pre># Step 3: Implement the Flyweight Factory<br>class FlyweightFactory:<br>    &quot;&quot;&quot;<br>    FlyweightFactory manages flyweight objects and ensures their uniqueness.<br>    &quot;&quot;&quot;<br><br>    _flyweights = {}<br><br>    @staticmethod<br>    def get_flyweight(key):<br>        &quot;&quot;&quot;<br>        Retrieve or create a flyweight object based on the provided key.<br>        &quot;&quot;&quot;<br>        if key not in FlyweightFactory._flyweights:<br>            FlyweightFactory._flyweights[key] = ConcreteFlyweight(key)<br>        return FlyweightFactory._flyweights[key]</pre><h4>Step 4: Define the client class</h4><p>Define a client class representing objects that use flyweight objects.</p><pre># Step 4: Define the client class<br>class Client:<br>    &quot;&quot;&quot;<br>    Client class represents objects that use flyweight objects.<br>    &quot;&quot;&quot;<br><br>    def __init__(self, key):<br>        self._flyweight = FlyweightFactory.get_flyweight(key)<br><br>    def operation(self, extrinsic_state):<br>        &quot;&quot;&quot;<br>        Perform an operation using the flyweight object and extrinsic state.<br>        &quot;&quot;&quot;<br>        return self._flyweight.operation(extrinsic_state)<br><br># Example usage<br>if __name__ == &quot;__main__&quot;:<br>    client1 = Client(&quot;shared&quot;)<br>    client2 = Client(&quot;shared&quot;)<br>    client3 = Client(&quot;unique&quot;)<br><br>    print(client1.operation(&quot;state 1&quot;))  # Output: ConcreteFlyweight: Intrinsic State - shared, Extrinsic State - state 1<br>    print(client2.operation(&quot;state 2&quot;))  # Output: ConcreteFlyweight: Intrinsic State - shared, Extrinsic State - state 2<br>    print(client3.operation(&quot;state 3&quot;))  # Output: ConcreteFlyweight: Intrinsic State - unique, Extrinsic State - state 3</pre><h4>GitHub Repo 🎉</h4><p>Explore all code examples and design pattern implementations on GitHub!</p><p><a href="https://github.com/AmirLavasani/python-design-patterns">GitHub - AmirLavasani/python-design-patterns: Explore design patterns using Python with code examples to solve common software challenges.</a></p><h3>Practical Example: Game Enemy Character</h3><h4>Step 1: Define the Flyweight Interface</h4><p>Define the abstract EnemyFlyweight interface with a render method.</p><pre>from abc import ABC, abstractmethod<br>import random<br><br># Step 1: Define the Flyweight interface<br>class EnemyFlyweight(ABC):<br>    &quot;&quot;&quot;<br>    Flyweight interface declares a method for accepting extrinsic state<br>    and performing operations based on it.<br>    &quot;&quot;&quot;<br><br>    @abstractmethod<br>    def render(self, position):<br>        &quot;&quot;&quot;<br>        Render method accepting extrinsic state as input.<br>        &quot;&quot;&quot;<br>        pass</pre><h4>Step 2: Create Concrete Flyweight Classes</h4><p>Create concrete flyweight classes (e.g., EnemyTypeA, EnemyTypeB) implementing the interface and storing intrinsic data like texture.</p><pre># Step 2: Create concrete flyweight classes<br>class EnemyTypeA(EnemyFlyweight):<br>    &quot;&quot;&quot;<br>    ConcreteFlyweight class for enemy type A.<br>    &quot;&quot;&quot;<br><br>    def __init__(self, texture):<br>        self._texture = texture<br><br>    def render(self, position):<br>        &quot;&quot;&quot;<br>        Render enemy type A with given position.<br>        &quot;&quot;&quot;<br>        print(f&quot;Rendering Enemy Type A at position {position} with texture: {self._texture}&quot;)<br><br>class EnemyTypeB(EnemyFlyweight):<br>    &quot;&quot;&quot;<br>    ConcreteFlyweight class for enemy type B.<br>    &quot;&quot;&quot;<br><br>    def __init__(self, texture):<br>        self._texture = texture<br><br>    def render(self, position):<br>        &quot;&quot;&quot;<br>        Render enemy type B with given position.<br>        &quot;&quot;&quot;<br>        print(f&quot;Rendering Enemy Type B at position {position} with texture: {self._texture}&quot;)</pre><h4>Step 3: Implement the Flyweight Factory</h4><p>Implement the EnemyFlyweightFactory to manage flyweight objects and ensure their uniqueness based on texture.</p><pre># Step 3: Implement the Flyweight Factory<br>class EnemyFlyweightFactory:<br>    &quot;&quot;&quot;<br>    FlyweightFactory manages flyweight objects and ensures their uniqueness.<br>    &quot;&quot;&quot;<br><br>    _flyweights = {}<br><br>    @staticmethod<br>    def get_flyweight(texture):<br>        &quot;&quot;&quot;<br>        Retrieve or create a flyweight object based on the provided texture.<br>        &quot;&quot;&quot;<br>        if texture not in EnemyFlyweightFactory._flyweights:<br>            if random.randint(0, 1) == 0:<br>                EnemyFlyweightFactory._flyweights[texture] = EnemyTypeA(texture)<br>            else:<br>                EnemyFlyweightFactory._flyweights[texture] = EnemyTypeB(texture)<br>        return EnemyFlyweightFactory._flyweights[texture]</pre><h4>Step 4: Define the client class</h4><p>Define the client class (e.g., GameEnvironment) representing objects that use flyweight objects. Instantiate the client class, add enemies with different textures and positions, and Render all enemies in the game environment using their respective flyweight objects.</p><pre># Step 4: Define the client class<br>class GameEnvironment:<br>    &quot;&quot;&quot;<br>    Client class represents objects that use flyweight objects.<br>    &quot;&quot;&quot;<br><br>    def __init__(self):<br>        self._enemies = []<br><br>    def add_enemy(self, texture, position):<br>        &quot;&quot;&quot;<br>        Add a new enemy to the game environment.<br>        &quot;&quot;&quot;<br>        flyweight = EnemyFlyweightFactory.get_flyweight(texture)<br>        self._enemies.append((flyweight, position))<br><br>    def render_enemies(self):<br>        &quot;&quot;&quot;<br>        Render all enemies in the game environment.<br>        &quot;&quot;&quot;<br>        for flyweight, position in self._enemies:<br>            flyweight.render(position)<br><br># Example usage<br>if __name__ == &quot;__main__&quot;:<br>    # Create game environment<br>    game = GameEnvironment()<br><br>    # Add enemies with different textures and positions<br>    game.add_enemy(&quot;texture_a&quot;, (10, 20))<br>    game.add_enemy(&quot;texture_b&quot;, (30, 40))<br>    game.add_enemy(&quot;texture_a&quot;, (50, 60))<br>    game.add_enemy(&quot;texture_b&quot;, (70, 80))<br><br>    # Render all enemies<br>    game.render_enemies()</pre><h3>Real-World Use Cases for Flyweight</h3><ol><li><strong>Graphics Processing Units (GPUs):</strong> <em>GPU frameworks like OpenGL and DirectX use Flyweight to efficiently manage textures and vertex data.</em></li><li><strong>Python Interning:</strong> <em>Python caches small integers and certain strings using Flyweight to optimize memory usage.</em></li><li><strong>Database Connection Pools:</strong> <em>Connection pool implementations in frameworks like Apache DBCP and HikariCP use Flyweight to manage and reuse database connections efficiently.</em></li><li><strong>Object Pooling Libraries:</strong> <em>Libraries like Apache Commons Pool and ObjectPool use Flyweight to pool and reuse objects, reducing object creation overhead.</em></li><li><strong>Caching Libraries:</strong> <em>Caching frameworks like Ehcache and Redis use Flyweight to cache objects and reduce memory usage.</em></li></ol><h3>Flyweight Best Practices and Potential Drawbacks</h3><h4>Pros:</h4><ol><li><strong>RAM Savings:</strong> <em>Significant RAM savings are possible, especially beneficial for programs with numerous similar objects.</em></li></ol><h4>Cons:</h4><ol><li><strong>CPU Overhead:</strong> <em>Potential trade-off between RAM and CPU cycles, particularly if recalculating context data for flyweight methods.</em></li><li><strong>Code Complexity:</strong> <em>Increased code complexity, potentially confusing for new team members due to the separation of entity states.</em></li></ol><h3>Flyweight’s Relations with Other Patterns</h3><p>The Flyweight pattern shares similarities and differences with several other design patterns:</p><h4>Flyweight and Composite</h4><p>Flyweight can be implemented to represent shared leaf nodes of the Composite tree, saving RAM by reducing the memory footprint of common objects.</p><h4>Flyweight vs. Facade</h4><p>While Flyweight focuses on creating many small objects efficiently, Facade concentrates on encapsulating complex subsystems into a single simplified interface.</p><h4>Flyweight vs. Singleton</h4><p>Although Flyweight may resemble Singleton if all shared states are reduced to one flyweight object, there are key differences.</p><p>Flyweight can have multiple instances with different intrinsic states, while Singleton allows only one instance. Additionally, Singleton objects can be mutable, whereas Flyweight objects are immutable.</p><h3>Conclusion</h3><p>In conclusion, we’ve explored the Flyweight pattern, which optimizes memory usage by sharing common data among multiple objects. We discussed its key components, including the Flyweight interface, Concrete Flyweight classes, Flyweight Factory, and Client. Additionally, we highlighted the pros and cons of using the Flyweight pattern.</p><p>We compared the Flyweight pattern to other related patterns such as Composite, Facade, and Singleton, illustrating its unique characteristics and applications. Finally, we implemented a practical example of a gaming character using the Flyweight pattern, demonstrating its efficiency in managing large numbers of similar objects.</p><p>Keep coding and exploring new design patterns! 👩‍💻</p><h3>Next on the Series 🚀</h3><p><a href="https://medium.com/@amirm.lavasani/design-patterns-in-python-template-method-1b76fb561c4a">Design Patterns in Python: Template Method</a></p><h3>Read More 📜</h3><ul><li><a href="https://medium.com/@amirm.lavasani/design-patterns-in-python-visitor-f20085b35d8b">Design Patterns in Python: Visitor</a></li><li><a href="https://medium.com/@amirm.lavasani/design-patterns-in-python-strategy-7b14f1c4c162">Design Patterns in Python: Strategy</a></li></ul><h3>The Series 🧭</h3><p><a href="https://medium.com/@amirm.lavasani/design-patterns-in-python-a-series-f502b7804ae5">Design Patterns in Python: A Series</a></p><h4>Explore the GitHub Repo 🎉</h4><p><a href="https://github.com/AmirLavasani/python-design-patterns">GitHub - AmirLavasani/python-design-patterns: Explore design patterns using Python with code examples to solve common software challenges.</a></p><h4>References</h4><ol><li><a href="https://www.goodreads.com/en/book/show/85009">Design Patterns: Elements of Reusable Object-Oriented Software</a> (Book)</li><li><a href="https://refactoring.guru/design-patterns/flyweight">refactoring.guru Flyweight</a></li><li><a href="https://www.goodreads.com/en/book/show/58128">Head First Design Patterns</a> (Book)</li><li><a href="https://www.digitalocean.com/community/tutorials/flyweight-design-pattern-java">Flyweight Design Pattern in Java</a></li><li><a href="https://www.pentalog.com/blog/design-patterns/flyweight-design-patterns/">The Flyweight Chronicles: How to Make Your Code Weightless!</a></li><li><a href="https://sourcemaking.com/design_patterns/flyweight">Flyweight Design Pattern</a></li><li><a href="https://gameprogrammingpatterns.com/flyweight.html">Game Programming Patterns Flyweight</a></li></ol><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=e7a7334f82b1" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Design Patterns in Python: Template Method]]></title>
            <link>https://medium.com/@amirm.lavasani/design-patterns-in-python-template-method-1b76fb561c4a?source=rss-2e98894ce1bf------2</link>
            <guid isPermaLink="false">https://medium.com/p/1b76fb561c4a</guid>
            <category><![CDATA[software-architecture]]></category>
            <category><![CDATA[programming]]></category>
            <category><![CDATA[template-method-pattern]]></category>
            <category><![CDATA[python]]></category>
            <category><![CDATA[design-patterns]]></category>
            <dc:creator><![CDATA[Amir Lavasani]]></dc:creator>
            <pubDate>Sat, 09 Mar 2024 08:37:46 GMT</pubDate>
            <atom:updated>2024-03-09T08:37:46.760Z</atom:updated>
            <content:encoded><![CDATA[<h4>TUTORIAL SERIES</h4><h4>Modular Algorithms</h4><blockquote><em>Have you encountered recurring coding challenges? Imagine having a toolbox of tried-and-true solutions readily available. That’s precisely what design patterns provide. In </em><a href="https://medium.com/@amirm.lavasani/design-patterns-in-python-a-series-f502b7804ae5"><em>this series</em></a><em>, we’ll explore what these patterns are and how they can elevate your coding skills.</em></blockquote><p><a href="https://medium.com/@amirm.lavasani/design-patterns-in-python-a-series-f502b7804ae5">Design Patterns in Python: A Series</a></p><h3>Understanding the Template Method Pattern</h3><h4>What is the Template Method Design Pattern?</h4><p>The Template Method is a behavioral design pattern that defines the skeleton of an algorithm in the superclass but lets subclasses override specific steps of the algorithm without changing its structure.</p><p>Simply put, the Template Method Pattern helps developers create a group of algorithms that share a common structure. It allows for easier management of complexity and encourages a systematic approach when designing related classes.</p><h4>When to Use the Template Method Pattern:</h4><p>Use the Template Method pattern when facing the following scenarios:</p><ol><li><strong>Extend Specific Steps:</strong> <em>Use when clients need to extend particular steps of an algorithm without altering its structure.</em></li><li><strong>Similar but Not Identical Algorithms:</strong> <em>Apply when dealing with multiple classes having almost identical algorithms with slight variations, making modification tedious.</em></li><li><strong>Eliminate Code Duplication:</strong> <em>Implement when turning a monolithic algorithm into a series of steps, allowing easy extension by subclasses, while consolidating similar implementations to eliminate code duplication.</em></li></ol><h4>Practical Example: Web Scraper Template</h4><p>We will implement a Web Scraper Template to showcase the capabilities of the template method in a practical example.</p><p>By encapsulating common steps like sending requests, parsing HTML, and extracting data, this pattern enables a structured and reusable approach to web scraping.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*VR5qPzwW8tmWyzbfYV5pWw.jpeg" /><figcaption>Dall-E generated image with the following concept: A flowchart depicting the standard process of the template method, with branches for customized steps</figcaption></figure><h3>Terminology and Key Components</h3><p>The template method pattern employs a straightforward class structure. We define an abstract template class with a TemplateMethod and concrete classes that can override specific steps.</p><ol><li><strong>Abstract Template Class:</strong> <em>Declares methods acting as steps in the algorithm and the template method, orchestrating these steps in a specific order. Steps may be either abstract or have default implementations.</em></li><li><strong>Concrete Template Classes:</strong> <em>Can override all steps but not the template method itself. These classes provide specific implementations for the declared steps, customizing the algorithm.</em></li></ol><figure><img alt="" src="https://cdn-images-1.medium.com/max/340/1*J8R2T-5NNNzltJxV0sctfg.png" /><figcaption>Template Method design pattern structure diagram. Image from <a href="https://refactoring.guru/design-patterns/template-method">refactoring.guru</a></figcaption></figure><h3>Template Method Implementation in Python</h3><h4>Step 1: Abstract Class (Template)</h4><p>The abstract class defines the structure of the algorithm through a template method, orchestrating the sequence of steps while declaring them as abstract methods, and allowing concrete classes to provide specific implementations.</p><pre>from abc import ABC, abstractmethod<br><br># Step 1: Abstract Class (Template)<br>class AbstractTemplate(ABC):<br>    def template_method(self):<br>        &quot;&quot;&quot;The template method orchestrating the steps.&quot;&quot;&quot;<br>        self.step_one()<br>        self.step_two()<br>        self.step_three()<br><br>    @abstractmethod<br>    def step_one(self):<br>        &quot;&quot;&quot;Abstract method representing the first step.&quot;&quot;&quot;<br>        pass<br><br>    @abstractmethod<br>    def step_two(self):<br>        &quot;&quot;&quot;Abstract method representing the second step.&quot;&quot;&quot;<br>        pass<br><br>    @abstractmethod<br>    def step_three(self):<br>        &quot;&quot;&quot;Abstract method representing the third step.&quot;&quot;&quot;<br>        pass</pre><h4>Step 2: Concrete Classes</h4><p>Concrete classes extend the abstract class, providing concrete implementations for each abstract method, thereby defining the specific steps of the algorithm.</p><pre># Step 2: Concrete Class 1<br>class ConcreteTemplateA(AbstractTemplate):<br>    def step_one(self):<br>        &quot;&quot;&quot;Concrete implementation for the first step in Template A.&quot;&quot;&quot;<br>        print(&quot;Performing initialization for Template A.&quot;)<br><br>    def step_two(self):<br>        &quot;&quot;&quot;Concrete implementation for the second step in Template A.&quot;&quot;&quot;<br>        print(&quot;Executing core logic for Template A.&quot;)<br><br>    def step_three(self):<br>        &quot;&quot;&quot;Concrete implementation for the third step in Template A.&quot;&quot;&quot;<br>        print(&quot;Finalizing and cleaning up for Template A.&quot;)</pre><pre># Step 3: Concrete Class 2<br>class ConcreteTemplateB(AbstractTemplate):<br>    def step_one(self):<br>        &quot;&quot;&quot;Concrete implementation for the first step in Template B.&quot;&quot;&quot;<br>        print(&quot;Setting up resources for Template B.&quot;)<br><br>    def step_two(self):<br>        &quot;&quot;&quot;Concrete implementation for the second step in Template B.&quot;&quot;&quot;<br>        print(&quot;Performing specialized processing for Template B.&quot;)<br><br>    def step_three(self):<br>        &quot;&quot;&quot;Concrete implementation for the third step in Template B.&quot;&quot;&quot;<br>        print(&quot;Cleaning up connections and resources for Template B.&quot;)</pre><h4>Main Section (Client Code)</h4><p>In the main section (client code), instances of concrete classes are created, and the template method is invoked on these instances to execute the algorithm, demonstrating the flexibility and customization allowed by the Template Method Pattern.</p><pre><br># Main Section<br>if __name__ == &quot;__main__&quot;:<br>    # Creating instances of concrete classes<br>    template_a = ConcreteTemplateA()<br>    template_b = ConcreteTemplateB()<br><br>    # Using the template method to perform steps<br>    print(&quot;Executing Template A:&quot;)<br>    template_a.template_method()<br><br>    print(&quot;\nExecuting Template B:&quot;)<br>    template_b.template_method()</pre><h4>GitHub Repo 🎉</h4><p>Explore all code examples and design pattern implementations on GitHub!</p><p><a href="https://github.com/AmirLavasani/python-design-patterns">GitHub - AmirLavasani/python-design-patterns: Explore design patterns using Python with code examples to solve common software challenges.</a></p><h3>Practical Example: Web Scraper Template</h3><h4>Step 1: Abstract Class (Web Scraper Template)</h4><p>The abstract class defines a template for web scraping with abstract methods representing common steps like sending HTTP requests, parsing HTML content, and extracting data, allowing concrete classes to provide specific implementations.</p><pre>from abc import ABC, abstractmethod<br>import requests<br>import urllib<br><br>from bs4 import BeautifulSoup<br><br><br># Step 1: Abstract Class (Web Scraper Template)<br>class WebScraperTemplate(ABC):<br>    @abstractmethod<br>    def send_request(self, url):<br>        &quot;&quot;&quot;Abstract method for sending HTTP requests.&quot;&quot;&quot;<br>        pass<br><br>    @abstractmethod<br>    def parse_html(self, content):<br>        &quot;&quot;&quot;Abstract method for parsing HTML content.&quot;&quot;&quot;<br>        pass<br><br>    @abstractmethod<br>    def extract_data(self, soup):<br>        &quot;&quot;&quot;Abstract method for extracting data from parsed HTML.&quot;&quot;&quot;<br>        pass<br><br>    # Template method orchestrating the steps<br>    def scrape_website(self, url):<br>        &quot;&quot;&quot;The template method for web scraping.&quot;&quot;&quot;<br>        content = self.send_request(url)<br>        soup = self.parse_html(content)<br>        data = self.extract_data(soup)<br>        return data</pre><h4>Step 2: Concrete Classes</h4><p>This concrete class extends the abstract web scraper template, providing a specific implementation using the requests library for sending HTTP requests and BeautifulSoup for HTML parsing, with a focus on extracting hyperlinks from a webpage.</p><pre># Step 2: Concrete Class 1 (RequestsAndBeautifulSoupWebScraper)<br>class RequestsAndBeautifulSoupWebScraper(WebScraperTemplate):<br>    def send_request(self, url):<br>        &quot;&quot;&quot;Concrete implementation for sending HTTP requests using requests library.&quot;&quot;&quot;<br>        response = requests.get(url)<br>        return response.content<br><br>    def parse_html(self, content):<br>        &quot;&quot;&quot;Concrete implementation for parsing HTML content using BeautifulSoup.&quot;&quot;&quot;<br>        soup = BeautifulSoup(content, &#39;html.parser&#39;)<br>        return soup<br><br>    def extract_data(self, soup):<br>        &quot;&quot;&quot;Concrete implementation for extracting data from parsed HTML.&quot;&quot;&quot;<br>        # Example: Extracting all hyperlinks from the webpage<br>        links = [a[&#39;href&#39;] for a in soup.find_all(&#39;a&#39;, href=True)]<br>        return links</pre><p>This concrete class also extends the web scraper template but uses urllib for sending HTTP requests and a custom parser for HTML content, showcasing an alternative approach to web scraping, and extracting email addresses from a webpage using regular expressions.</p><pre># Step 3: Concrete Class 2 (UrllibAndRegexWebScraper)<br>class UrllibAndRegexWebScraper(WebScraperTemplate):<br>    def send_request(self, url):<br>        &quot;&quot;&quot;Concrete implementation for sending HTTP requests using urllib.&quot;&quot;&quot;<br>        with urllib.request.urlopen(url) as response:<br>            return response.read()<br><br>    def parse_html(self, content):<br>        &quot;&quot;&quot;Concrete implementation for parsing HTML content using custom parser.&quot;&quot;&quot;<br>        # Custom HTML parsing logic<br>        return content<br><br>    def extract_data(self, content):<br>        &quot;&quot;&quot;Concrete implementation for extracting data using regex.&quot;&quot;&quot;<br>        import re<br>        # Example: Extracting all email addresses from the webpage<br>        emails = re.findall(r&#39;\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}\b&#39;, content.decode(&#39;utf-8&#39;))<br>        return emails</pre><h4>Client Code</h4><p>Creates instances of concrete classes, invoking the template method for flexible web scraping with varied underlying algorithms.</p><pre># Main Section (Client Code)<br>if __name__ == &quot;__main__&quot;:<br>    # Creating instances of the concrete classes<br>    web_scraper_requests_beautifulsoup = RequestsAndBeautifulSoupWebScraper()<br>    web_scraper_urllib_regex = UrllibAndRegexWebScraper()<br><br>    # Using the template method to scrape websites<br>    target_url = &quot;https://example.com&quot;<br><br>    print(&quot;Scraped Data using RequestsAndBeautifulSoupWebScraper:&quot;)<br>    data_requests_beautifulsoup = web_scraper_requests_beautifulsoup.scrape_website(target_url)<br>    for link in data_requests_beautifulsoup:<br>        print(link)<br><br>    print(&quot;\nScraped Data using UrllibAndRegexWebScraper:&quot;)<br>    data_urllib_regex = web_scraper_urllib_regex.scrape_website(target_url)<br>    for email in data_urllib_regex:<br>        print(email)</pre><h3>Real-World Use Cases for Template Method</h3><ol><li><strong>Django Web Framework (Python):</strong> <em>Employs Template Method in view classes for handling HTTP requests, enabling developers to customize specific steps of request processing.</em></li><li><strong>Vue.js Frontend Framework (JavaScript):</strong> <em>Implements Template Method in component lifecycle hooks, allowing developers to customize behavior during different phases of a component’s life.</em></li><li><strong>TensorFlow Machine Learning Library (Python):</strong> <em>Uses Template Method in model training classes, providing a standardized structure while allowing customization of training steps.</em></li><li><strong>WordPress Theme Development (PHP):</strong> <em>Utilizes Template Method in theme classes, allowing customization of the layout, header, and footer within a consistent theme structure.</em></li><li><strong>Angular Framework (TypeScript):</strong> <em>Incorporates Template Method in component lifecycle hooks, providing a standardized structure for initialization, change detection, and destruction.</em></li></ol><h3>Template Method Best Practices and Potential Drawbacks</h3><p>When leveraging the Template Method Design Pattern, it’s vital to weigh its advantages and potential challenges:</p><h4>Pros</h4><ol><li><strong>Selective Overrides:</strong> <em>Clients can override specific parts of a large algorithm, reducing the impact of changes on other sections.</em></li><li><strong>Code Reusability:</strong> <em>Duplicate code can be consolidated into a superclass, promoting a more maintainable codebase.</em></li></ol><h4>Cons</h4><ol><li><strong>Client Limitations:</strong> <em>Some clients may find their flexibility constrained by the predefined algorithm structure.</em></li><li><strong>Liskov Substitution Principle:</strong> <em>Suppressing a default step implementation in a subclass could violate the Liskov Substitution Principle.</em></li><li><strong>Maintenance Challenges:</strong> <em>Template methods become harder to maintain with an increasing number of steps.</em></li></ol><h4>Best Practices</h4><ol><li><strong>Clear Abstractions:</strong> <em>Establish clear abstractions for components to maintain a cohesive and understandable interface.</em></li><li><strong>Use of Interfaces:</strong> <em>Implement interfaces to ensure uniformity among components interacting with the template.</em></li></ol><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*fUbvSesgBMBNkhot8gEduA.jpeg" /><figcaption>Dall-E generated image with the following concept: AI ego gains consciousness and comprehends the concept of “I”</figcaption></figure><h3>Template Method’s Relations with Other Patterns</h3><p>When considering the Template Method pattern, it’s crucial to recognize its connections with other design patterns, each addressing distinct aspects of software architecture.</p><h4>Template vs. Factory Method Pattern</h4><p>The Factory Method is a specialized form of the Template Method, and it can also serve as a step within a larger Template Method.</p><p>While both involve object creation, the Template Method focuses on algorithmic structure, while the Factory Method is centered around object instantiation.</p><h4>Template Method vs. Strategy Pattern</h4><p>Template Method and Strategy patterns diverge in their approach to modifying object behavior. Template Method, reliant on inheritance, facilitates changes by extending parts of an algorithm in subclasses, operating at the class level.</p><p>Conversely, the Strategy pattern, relying on composition, enables runtime behavior alterations at the object level by supplying different strategies.</p><h3>Conclusion</h3><p>In concluding our journey through the Template Method Pattern in Python, we’ve delved into a pattern that provides a blueprint for algorithmic structures with customizable steps.</p><p>The key components, including the abstract class, concrete subclasses, and the template method itself, showcase a robust design for algorithm definition and refinement. We’ve explored the pros and cons of the Template Method, weighing its benefits in algorithm customization against potential limitations.</p><p>Additionally, we implemented a practical Web Scraper Template, demonstrating the pattern’s effectiveness in a real-world scenario.</p><p>Happy coding! 👩‍💻</p><h3>Next on the Series 🚀</h3><p><a href="https://medium.com/@amirm.lavasani/design-patterns-in-python-visitor-f20085b35d8b">Design Patterns in Python: Visitor</a></p><h3>Read More 📜</h3><ul><li><a href="https://medium.com/@amirm.lavasani/design-patterns-in-python-strategy-7b14f1c4c162">Design Patterns in Python: Strategy</a></li><li><a href="https://medium.com/@amirm.lavasani/design-patterns-in-python-observer-ac50bbf861b5">Design Patterns in Python: Observer</a></li></ul><h3>The Series 🧭</h3><p><a href="https://medium.com/@amirm.lavasani/design-patterns-in-python-a-series-f502b7804ae5">Design Patterns in Python: A Series</a></p><h4>Explore the GitHub Repo 🎉</h4><p><a href="https://github.com/AmirLavasani/python-design-patterns">GitHub - AmirLavasani/python-design-patterns: Explore design patterns using Python with code examples to solve common software challenges.</a></p><h4>References</h4><ol><li><a href="https://www.goodreads.com/en/book/show/85009">Design Patterns: Elements of Reusable Object-Oriented Software</a> (Book)</li><li><a href="https://refactoring.guru/design-patterns/template-method">refactoring.guru Template Method</a></li><li><a href="https://www.goodreads.com/en/book/show/58128">Head First Design Patterns</a> (Book)</li><li><a href="https://www.digitalocean.com/community/tutorials/template-method-design-pattern-in-java">Template Method Design Pattern in Java</a></li><li><a href="https://sourcemaking.com/design_patterns/template_method">Template Method Design Pattern</a></li></ol><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=1b76fb561c4a" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Design Patterns in Python: Visitor]]></title>
            <link>https://medium.com/@amirm.lavasani/design-patterns-in-python-visitor-f20085b35d8b?source=rss-2e98894ce1bf------2</link>
            <guid isPermaLink="false">https://medium.com/p/f20085b35d8b</guid>
            <category><![CDATA[programming]]></category>
            <category><![CDATA[design-patterns]]></category>
            <category><![CDATA[visitor-pattern]]></category>
            <category><![CDATA[python]]></category>
            <category><![CDATA[software-architecture]]></category>
            <dc:creator><![CDATA[Amir Lavasani]]></dc:creator>
            <pubDate>Wed, 14 Feb 2024 07:35:54 GMT</pubDate>
            <atom:updated>2024-02-14T09:16:44.549Z</atom:updated>
            <content:encoded><![CDATA[<h4>TUTORIAL SERIES</h4><h4>Structured Processing</h4><blockquote><em>Have you encountered recurring coding challenges? Imagine having a toolbox of tried-and-true solutions readily available. That’s precisely what design patterns provide. In </em><a href="https://medium.com/@amirm.lavasani/design-patterns-in-python-a-series-f502b7804ae5"><em>this series</em></a><em>, we’ll explore what these patterns are and how they can elevate your coding skills.</em></blockquote><p><a href="https://medium.com/@amirm.lavasani/design-patterns-in-python-a-series-f502b7804ae5">Design Patterns in Python: A Series</a></p><h3>Understanding the Visitor Pattern</h3><h4>What is the Visitor Design Pattern?</h4><p>The Visitor Design Pattern is a behavioral design paradigm that defines a mechanism for traversing elements in an object structure and performing operations on them without altering their structure. It provides a means to add new operations to existing object structures without modifying those structures.</p><p>In simpler terms, the Visitor pattern allows you to define new functionalities (operations) that can be applied to a set of related classes, promoting extensibility without modifying the classes themselves.</p><h4>When to Use the Visitor Pattern:</h4><ol><li><strong>Multiple Operations on Object Structures:</strong> <em>Execute various operations on complex object structures without modifying their classes.</em></li><li><strong>Adding New Operations Without Modifying Classes:</strong> <em>Easily extend functionalities by adding new operations to existing classes without altering them.</em></li><li><strong>Operations Depending on the Type of Elements:</strong> <em>Implement behaviors that vary based on the type of elements in the object structure.</em></li></ol><h4>The Problem</h4><p>Consider an application managing a vast graph representing an intricate network of interconnected nodes, each denoting distinct entities such as users, transactions, or products.</p><p>The challenge arises when tasked with implementing a logging mechanism to record the activities of these nodes. The initial plan involves adding a logging method to each node class, a seemingly straightforward solution.</p><p>However, modifying existing node classes in a production environment poses risks. Additionally, embedding logging behavior within classes primarily designed for core functionalities raises questions about the coherence of such an approach.</p><h4>The Solution: Visitor</h4><p>The Visitor pattern resolves this by recommending a separate visitor class for new behavior. This avoids modifying existing classes, reducing risks, and ensuring a clean separation of concerns.</p><p>With the Visitor pattern, logging methods for each node type are defined in the visitor class, and dynamically executed via the accept method. This approach allows the addition of new logging behaviors without extensive modifications to existing classes.</p><h4>Practical Example: Document Exporter</h4><p>In this practical example, we export document elements like paragraphs, headings, and images to various formats without altering their individual classes.</p><p>The Visitor Pattern ensures a modular design by defining a common interface for exporters, allowing dynamic execution of export methods based on element types.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*IhZU_vIKGHEVL_PSJEfBZQ.jpeg" /><figcaption>Dall-E generated image with the following concept: Various doors with unique symbols, each representing an element to be visited.</figcaption></figure><h3>Terminology and Key Components</h3><p>Understanding the fundamental components of the Visitor pattern is essential for effective implementation. Here are the key components involved:</p><ol><li><strong>Visitor Interface: </strong><em>Declares visiting methods for concrete elements, allowing methods with the same names in languages supporting overloading, but requiring different parameter types.</em></li><li><strong>Concrete Visitor:</strong> <em>Implements behavior variations for different element classes, enabling tailored actions during visits.</em></li><li><strong>Element Interface: </strong><em>The Element interface includes an </em><em>accept method with one parameter specifying the type of the visitor interface for visitor acceptance.</em></li><li><strong>Concrete Element:</strong> <em>Implements the </em><em>accept method to redirect calls to the appropriate visitor methods, ensuring specific handling for each element.</em></li><li><strong>Client:</strong> <em>Represents a collection, interacting with elements through an abstract interface and orchestrating visitor acceptance without detailed knowledge of concrete classes.</em></li></ol><figure><img alt="" src="https://cdn-images-1.medium.com/max/520/1*yTXMtYd-ZTuWV3lWvBUtyw.png" /><figcaption>Visitor design pattern structure diagram. Image from <a href="https://refactoring.guru/design-patterns/visitor">refactoring.guru</a></figcaption></figure><h3>Visitor Pattern Implementation in Python</h3><p>here is a step-by-step approach, implementing each of the five key components of the Visitor pattern.</p><h4>Step 1: Visitor Interface</h4><p>Visitor is an abstract class defining visiting methods for each concrete element.</p><pre>from abc import ABC, abstractmethod<br><br># Step 1: Visitor Interface<br>class Visitor(ABC):<br>    @abstractmethod<br>    def visit_concrete_element_a(self, element_a):<br>        pass<br><br>    @abstractmethod<br>    def visit_concrete_element_b(self, element_b):<br>        pass</pre><h4>Step 2: Concrete Visitors</h4><p>ConcreteVisitorA and ConcreteVisitorB implement specific behaviors for visiting each concrete element.</p><pre># Concrete Visitor A<br>class ConcreteVisitorA(Visitor):<br>    def visit_concrete_element_a(self, element_a):<br>        print(f&quot;Visitor A visiting {element_a}&quot;)<br><br>    def visit_concrete_element_b(self, element_b):<br>        print(f&quot;Visitor A visiting {element_b}&quot;)<br><br><br># Concrete Visitor B<br>class ConcreteVisitorB(Visitor):<br>    def visit_concrete_element_a(self, element_a):<br>        print(f&quot;Visitor B visiting {element_a}&quot;)<br><br>    def visit_concrete_element_b(self, element_b):<br>        print(f&quot;Visitor B visiting {element_b}&quot;)</pre><h4>Step 3: Element Interface</h4><p>Element is an abstract class defining the accept method for accepting visitors.</p><pre># Step 3: Element Interface<br>class Element(ABC):<br>    @abstractmethod<br>    def accept(self, visitor):<br>        pass</pre><h4>Step 4: Concrete Elements</h4><p>ConcreteElementA and ConcreteElementB implement the accept method and define their unique operations.</p><pre># Step 4: Concrete Elements<br>class ConcreteElementA(Element):<br>    def accept(self, visitor):<br>        visitor.visit_concrete_element_a(self)<br><br>    def operation_a(self):<br>        return &quot;Operation A&quot;<br><br><br>class ConcreteElementB(Element):<br>    def accept(self, visitor):<br>        visitor.visit_concrete_element_b(self)<br><br>    def operation_b(self):<br>        return &quot;Operation B&quot;</pre><h4>Client Code</h4><p>Demonstrates the usage of concrete elements and visitors.</p><pre># Client Code<br>if __name__ == &quot;__main__&quot;:<br>    # Creating concrete elements<br>    element_a = ConcreteElementA()<br>    element_b = ConcreteElementB()<br><br>    # Creating concrete visitors<br>    visitor_a = ConcreteVisitorA()<br>    visitor_b = ConcreteVisitorB()<br><br>    # Accepting visitors<br>    element_a.accept(visitor_a)<br>    element_b.accept(visitor_a)<br><br>    element_a.accept(visitor_b)<br>    element_b.accept(visitor_b)</pre><h3>Practical Example: Document Exporter</h3><h4>Step 1: Define the Visitor Interface</h4><p>Define the Visitor Interface with methods corresponding to each type of element in the document structure.</p><pre># Step 1: Define the Visitor Interface<br>class Exporter:<br>    def export_paragraph(self, paragraph):<br>        pass<br><br>    def export_heading(self, heading):<br>        pass<br><br>    def export_image(self, image):<br>        pass</pre><h4>Step 2: Implement Concrete Visitors</h4><p>Implement Concrete Visitors (HTMLExporter and PDFExporter) providing specific behavior for each type of element.</p><pre># Step 2: Implement Concrete Visitors<br>class HTMLExporter(Exporter):<br>    def export_paragraph(self, paragraph):<br>        return f&quot;&lt;p&gt;{paragraph.content}&lt;/p&gt;&quot;<br><br>    def export_heading(self, heading):<br>        return f&quot;&lt;h{heading.level}&gt;{heading.text}&lt;/h{heading.level}&gt;&quot;<br><br>    def export_image(self, image):<br>        return f&#39;&lt;img src=&quot;{image.source}&quot; alt=&quot;{image.alt}&quot;&gt;&#39;</pre><pre>class PDFExporter(Exporter):<br>    def export_paragraph(self, paragraph):<br>        return f&quot;PDF Paragraph: {paragraph.content}&quot;<br><br>    def export_heading(self, heading):<br>        return f&quot;PDF Heading ({heading.level}): {heading.text}&quot;<br><br>    def export_image(self, image):<br>        return f&#39;PDF Image: {image.alt}&#39;</pre><h4>Step 3: Define Element Interface</h4><p>Define the Element Interface with an accept method to allow visitors to operate on elements.</p><pre># Step 3: Define Element Interface<br>class Element:<br>    def accept(self, visitor):<br>        pass</pre><h4>Step 4: Implement Concrete Elements</h4><p>Implement concrete elements (Paragraph, Heading, Image) with an accept method to let visitors operate on them.</p><pre># Step 4: Implement Concrete Elements<br>class Paragraph(Element):<br>    def __init__(self, content):<br>        self.content = content<br><br>    def accept(self, visitor):<br>        return visitor.export_paragraph(self)<br><br><br>class Heading(Element):<br>    def __init__(self, level, text):<br>        self.level = level<br>        self.text = text<br><br>    def accept(self, visitor):<br>        return visitor.export_heading(self)<br><br><br>class Image(Element):<br>    def __init__(self, source, alt):<br>        self.source = source<br>        self.alt = alt<br><br>    def accept(self, visitor):<br>        return visitor.export_image(self)</pre><h4>Step 5: Client Code</h4><p>Implement the Client Code (Document) with an accept method to iterate through elements and let the visitor operate on them.</p><p>Create instances of Concrete Visitors (HTMLExporter, PDFExporter) and use them to export a Document with different types of elements, demonstrating the Visitor Pattern in action.</p><pre># Step 5: Client Code<br>class Document:<br>    def __init__(self, elements):<br>        self.elements = elements<br><br>    def accept(self, visitor):<br>        result = []<br>        for element in self.elements:<br>            result.append(element.accept(visitor))<br>        return result</pre><pre># Usage<br>html_exporter = HTMLExporter()<br>pdf_exporter = PDFExporter()<br><br>document = Document([<br>    Paragraph(&quot;This is a paragraph.&quot;),<br>    Heading(1, &quot;Main Heading&quot;),<br>    Image(&quot;image.jpg&quot;, &quot;A beautiful image&quot;)<br>])<br><br># Export to HTML<br>html_result = document.accept(html_exporter)<br>print(&quot;HTML Export:&quot;)<br>print(&#39;\n&#39;.join(html_result))<br>print(&quot;\n&quot;)<br><br># Export to PDF<br>pdf_result = document.accept(pdf_exporter)<br>print(&quot;PDF Export:&quot;)<br>print(&#39;\n&#39;.join(pdf_result))</pre><h4>GitHub Repo 🎉</h4><p>Explore all code examples and design pattern implementations on GitHub!</p><p><a href="https://github.com/AmirLavasani/python-design-patterns">GitHub - AmirLavasani/python-design-patterns: Explore design patterns using Python with code examples to solve common software challenges.</a></p><h3>Real-World Use Cases for Visitor Pattern</h3><ol><li><strong>Document Object Model (DOM) Manipulation in JavaScript:</strong> <em>JavaScript libraries like jQuery use the Visitor pattern to traverse and manipulate the DOM efficiently, enabling dynamic updates to web pages</em>.</li><li><strong>Python Abstract Syntax Tree (AST) Module:</strong> <em>Python’s </em><em>ast module utilizes the Visitor pattern to traverse and analyze Python code at the abstract syntax tree level, providing a foundation for tools like linters and code analyzers.</em></li><li><strong>OpenGL Scene Graph Traversal:</strong> <em>In graphics libraries like OpenGL, the Visitor pattern is employed to traverse scene graphs efficiently, enabling the rendering of complex 3D scenes.</em></li><li><strong>Mozilla SpiderMonkey JavaScript Engine:</strong> <em>SpiderMonkey, the JavaScript engine used in Mozilla Firefox, applies the Visitor pattern for traversing abstract syntax trees during JavaScript code execution.</em></li><li><strong>Git Version Control System:</strong> <em>Git employs the Visitor pattern in its internal object traversal mechanisms, facilitating efficient commit and tree operations.</em></li></ol><h3>Visitor Best Practices and Potential Drawbacks</h3><p>When employing the Visitor pattern, several best practices and considerations contribute to its effective utilization:</p><h4>Best Practices:</h4><ol><li><strong>Operation on Complex Structures:</strong> <em>Use the Visitor when you need to perform an operation on all elements of a complex object structure, like an object tree.</em></li><li><strong>Business Logic Cleanup:</strong> <em>Employ the Visitor pattern to clean up the business logic of auxiliary behaviors, allowing primary classes to focus on their main responsibilities.</em></li><li><strong>Selective Behavior Implementation:</strong> <em>Use the pattern when a behavior is relevant only in certain classes of a hierarchy, extracting it into a separate visitor class and implementing only the necessary visiting methods.</em></li></ol><h4>Drawbacks:</h4><ol><li><strong>Maintenance Overhead:</strong> <em>Updating all visitors when a class is added to or removed from the element hierarchy can introduce maintenance overhead.</em></li><li><strong>Limited Access to Private Fields:</strong> <em>Visitors might lack access to the private fields and methods of elements, potentially restricting their functionality.</em></li></ol><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*P-HBmk306fGCDTVAkJPfPQ.jpeg" /><figcaption>Dall-E generated image with the following concept: AI ego gains consciousness and comprehends the concept of “I”.</figcaption></figure><h3>Visitor Pattern’s Relations with Other Patterns</h3><p>When considering the Visitor pattern, its relations with other patterns become apparent, offering unique advantages in certain scenarios:</p><h4>Visitor vs. Command Pattern:</h4><ul><li><strong>Similarity:</strong> <em>Treat Visitor as a potent version of the Command pattern. Both enable objects to execute operations over various objects of different classes.</em></li><li><strong>Distinction:</strong> <em>While Command focuses on encapsulating requests as objects, Visitor extends this concept by executing operations over diverse classes of objects.</em></li></ul><h4>Visitor with Composite Pattern:</h4><ul><li><strong>Usage:</strong> <em>Utilize Visitor to execute an operation over an entire Composite tree. This synergistic combination allows performing operations on complex structures seamlessly.</em></li></ul><h4>3. Visitor with Iterator Pattern:</h4><ul><li><strong>Collaboration:</strong> <em>Combine Visitor with Iterator to traverse a complex data structure and execute operations over its elements, even if they have different classes. This collaboration enhances flexibility in processing diverse elements.</em></li></ul><h3>Conclusion</h3><p>Concluding our exploration of the Visitor Pattern, this design pattern excels in traversing and performing operations on diverse objects within complex structures. The Visitor <em>Interface</em>, <em>Concrete Visitors</em>, and <em>Elements </em>create a modular and focused approach, enabling dynamic behavior changes.</p><p>Understanding its pros, cons, and comparisons with related patterns equips developers to make informed choices. The Visitor pattern’s adaptability proves valuable for scenarios requiring dynamic, class-specific behaviors.</p><p>Whether traversing abstract syntax trees or performing complex operations, the Visitor pattern stands out as a versatile solution, enhancing flexibility and maintainability in your codebase.</p><p>Happy coding! 👩‍💻</p><h3>Next on the Series 🚀</h3><p><a href="https://medium.com/@amirm.lavasani/design-patterns-in-python-strategy-7b14f1c4c162">Design Patterns in Python: Strategy</a></p><h4>Explore the GitHub Repo 🎉</h4><p><a href="https://github.com/AmirLavasani/python-design-patterns">GitHub - AmirLavasani/python-design-patterns: Explore design patterns using Python with code examples to solve common software challenges.</a></p><h3>Read More 📜</h3><ul><li><a href="https://medium.com/@amirm.lavasani/design-patterns-in-python-observer-ac50bbf861b5">Design Patterns in Python: Observer</a></li><li><a href="https://medium.com/@amirm.lavasani/design-patterns-in-python-memento-5b8f94d84bc3">Design Patterns in Python: Memento</a></li></ul><h3>The Series 🧭</h3><p><a href="https://medium.com/@amirm.lavasani/design-patterns-in-python-a-series-f502b7804ae5">Design Patterns in Python: A Series</a></p><h4>References</h4><ol><li><a href="https://www.goodreads.com/en/book/show/85009">Design Patterns: Elements of Reusable Object-Oriented Software</a> (Book)</li><li><a href="https://refactoring.guru/design-patterns/visitor">refactoring.guru Visitor</a></li><li><a href="https://www.goodreads.com/en/book/show/58128">Head First Design Patterns</a> (Book)</li><li><a href="https://www.digitalocean.com/community/tutorials/visitor-design-pattern-java">Visitor Design Pattern in Java</a></li><li><a href="https://www.scaler.com/topics/design-patterns/visitor-design-pattern/">Scaler Visitor Design Pattern</a></li></ol><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=f20085b35d8b" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Classic Machine Learning in Python: K-Nearest Neighbors (KNN)]]></title>
            <link>https://medium.com/@amirm.lavasani/classic-machine-learning-in-python-k-nearest-neighbors-knn-a06fbfaaf80a?source=rss-2e98894ce1bf------2</link>
            <guid isPermaLink="false">https://medium.com/p/a06fbfaaf80a</guid>
            <category><![CDATA[machine-learning]]></category>
            <category><![CDATA[python]]></category>
            <category><![CDATA[ai]]></category>
            <category><![CDATA[pattern-recognition]]></category>
            <category><![CDATA[knn]]></category>
            <dc:creator><![CDATA[Amir Lavasani]]></dc:creator>
            <pubDate>Tue, 06 Feb 2024 09:13:09 GMT</pubDate>
            <atom:updated>2024-05-08T05:54:58.915Z</atom:updated>
            <content:encoded><![CDATA[<h4>Neural Odyssey Series</h4><h4>Proximity-Based Predictions</h4><h3>What is KNN?</h3><p>KNN relies on a straightforward principle: when given a new, unknown data point, it looks at the <strong>K</strong> nearest labeled data points and assigns the most common label among them to the new point.</p><p>This <strong>closeness</strong> is determined by a distance metric, commonly Euclidean or Manhattan distance.</p><h3>The Core Principle of Proximity-Based Learning</h3><p>At the core of proximity-based learning, such as the K-Nearest Neighbors (KNN) algorithm, lies a fundamental concept: <strong>closeness dictates similarity</strong>.</p><h4>Grasping Similarity via Proximity</h4><p>The concept translates into the algorithm’s behavior by seeking the closest ‘neighbors’ — data points that share proximity — to make decisions about new, unseen data. By assuming that nearby points are alike, the algorithm infers patterns and assigns labels based on this proximity.</p><h4>Decision Boundaries: A Result of Proximity</h4><p>The algorithm doesn’t just predict outcomes; it also delineates decision boundaries. These boundaries partition the feature space into regions, where each region signifies a particular class or label. Think of it as virtual borders drawn based on the proximity of data points.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*cfjz1fvr_OG-89djzp_GTA.jpeg" /><figcaption>Dall-E generated image with the following concept: Various data points forming groups or clusters, with neighboring points appearing closer together</figcaption></figure><h3>Anatomy of the KNN Algorithm</h3><ol><li><strong>Neighbor identification:</strong> KNN identifies ‘k’ nearest neighbors to a query point based on their proximity.</li><li><strong>A decision by the majority:</strong> It predicts by a majority vote among the neighbors for classification or averaging for regression.</li><li><strong>No explicit training phase:</strong> KNN’s lazy learning means no explicit training; it stores the entire dataset for inference.</li><li><strong>Impact of k-value:</strong> The <strong>k</strong> parameter influences model complexity and can affect overfitting or underfitting.</li></ol><h3>Choosing the Right Distance Metrics in KNN</h3><p>Each distance metric provides a unique perspective in determining proximity and contributes distinct decision boundaries within the KNN algorithm.</p><p>Understanding their characteristics aids in selecting the most appropriate metric for a given dataset.</p><p>Let&#39;s explore some key distance metrics used in KNN:</p><h4>Euclidean Distance (p=2)</h4><p>The most prevalent and straightforward distance measure, exclusively applicable to real-valued vectors.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/403/1*xON82uRMjuibLKxBoy-kAw.png" /><figcaption><strong>Formula:</strong> The Euclidean distance is calculated as the straight-line distance between the query point and the target point</figcaption></figure><h4>Manhattan Distance (p=1)</h4><p>Often known as a taxicab or city block distance, this metric calculates the absolute value between two points.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/326/1*feoysTeJsLURleGYwIpbiw.png" /><figcaption><strong>Formula:</strong> The Manhattan distance is computed by summing the absolute differences between coordinates</figcaption></figure><h4>Minkowski Distance</h4><p>A generalized form that encompasses both Euclidean and Manhattan distances, allowing the creation of various distance metrics based on the parameter p.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/395/1*IXENU0o1Z8ViUwaxdK2emQ.png" /><figcaption><strong>Formula:</strong> The Minkowski distance equation adapts based on the value of p</figcaption></figure><h4>Hamming Distance</h4><p>Tailored for Boolean or string vectors, identifying discrepancies between vectors. Commonly referred to as the overlap metric.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/308/1*QpFUXspAKkWcKR1YnPjAYA.png" /><figcaption><strong>Formula:</strong> The Hamming distance quantifies differences between vectors of equal length, counting the positions where the vectors do not match</figcaption></figure><h3>Coding KNN in Python from Scratch</h3><p>Implementing the K-Nearest Neighbors (KNN) algorithm from scratch allows a deep dive into its mechanics.</p><p>Let’s break down the process into distinct parts and code each step comprehensively.</p><h4>Part 1: Distance Calculation</h4><p>The core of KNN involves measuring distances between data points. In this step, we’ll create a function to compute the Euclidean distance between two points.</p><pre>def euclidean_distance(point1, point2):<br>    &quot;&quot;&quot;<br>    Calculate the Euclidean distance between two points.<br><br>    Parameters:<br>    point1 : list or array-like<br>        Coordinates of the first point.<br>    point2 : list or array-like<br>        Coordinates of the second point.<br><br>    Returns:<br>    distance : float<br>        The Euclidean distance between the two points.<br>    &quot;&quot;&quot;<br>    # Ensure both points have the same dimensions<br>    assert len(point1) == len(point2), &quot;Points should have the same dimensions.&quot;<br>    <br>    # Compute the Euclidean distance<br>    distance = sum((p1 - p2) ** 2 for p1, p2 in zip(point1, point2)) ** 0.5<br>    return distance</pre><h4>Part 2: Finding Nearest Neighbors</h4><p>Next, let’s write a function to find the ‘k’ nearest neighbors of a query point within a dataset.</p><pre>def find_neighbors(X_train, query_point, k):<br>    &quot;&quot;&quot;<br>    Find the &#39;k&#39; nearest neighbors of a query point within a dataset.<br><br>    Parameters:<br>    X_train : list or array-like<br>        Training dataset containing features.<br>    query_point : list or array-like<br>        Coordinates of the query point.<br>    k : int<br>        Number of neighbors to find.<br><br>    Returns:<br>    neighbors : list<br>        List of indices of the &#39;k&#39; nearest neighbors.<br>    &quot;&quot;&quot;<br>    distances = []<br>    <br>    # Calculate distance from the query point to each point in the training set<br>    for i, data_point in enumerate(X_train):<br>        distance = euclidean_distance(query_point, data_point)<br>        distances.append((i, distance))<br>    <br>    # Sort distances in ascending order<br>    distances.sort(key=lambda x: x[1])<br>    <br>    # Get indices of the &#39;k&#39; nearest neighbors<br>    neighbors = [index for index, _ in distances[:k]]<br>    return neighbors</pre><h4>Part 3: Predicting the Class</h4><p>Finally, let’s create a function to predict the class of a query point based on the majority class among its nearest neighbors.</p><pre>def predict(X_train, y_train, query_point, k):<br>    &quot;&quot;&quot;<br>    Predict the class of a query point based on the majority class among its nearest neighbors.<br><br>    Parameters:<br>    X_train : list or array-like<br>        Training dataset containing features.<br>    y_train : list or array-like<br>        Training dataset containing labels.<br>    query_point : list or array-like<br>        Coordinates of the query point.<br>    k : int<br>        Number of neighbors to consider.<br><br>    Returns:<br>    predicted_class : int or str<br>        Predicted class label for the query point.<br>    &quot;&quot;&quot;<br>    neighbors = find_neighbors(X_train, y_train, query_point, k)<br>    neighbor_labels = [y_train[i] for i in neighbors]<br>    <br>    # Count occurrences of each label among neighbors<br>    label_counts = {}<br>    for label in neighbor_labels:<br>        if label in label_counts:<br>            label_counts[label] += 1<br>        else:<br>            label_counts[label] = 1<br>    <br>    # Get the label with the highest count<br>    predicted_class = max(label_counts, key=label_counts.get)<br>    return predicted_class</pre><h3>Exploring Wine Quality Classification with KNN</h3><h4>Introduction to the Dataset</h4><p>The <a href="https://archive.ics.uci.edu/dataset/186/wine+quality">wine quality dataset</a> comprises 11 features like acidity, residual sugar, pH, and alcohol content, aiming to predict wine quality on a scale from 1 to 10. With 4898 samples, this dataset serves as a playground for exploring classification techniques.</p><h4>Static K-value: Starting Point</h4><p>In this phase, we initiate our exploration by reading the dataset, splitting it into training and testing sets, and applying a KNeighborsClassifier from scikit-learn with a static k-value of 15.</p><pre>import pandas as pd<br>from sklearn.model_selection import train_test_split, GridSearchCV<br>from sklearn.neighbors import KNeighborsClassifier<br>from sklearn.ensemble import BaggingClassifier<br>from sklearn.metrics import accuracy_score<br>import matplotlib.pyplot as plt<br>import seaborn as sns<br><br><br>def read_data(file_name):<br>    # Load the dataset with semicolon delimiter<br>    data = pd.read_csv(file_name, delimiter=&#39;;&#39;)<br>    return data<br><br>def split_data(data):<br>    # Extract features and labels<br>    X = data.drop(&#39;quality&#39;, axis=1)<br>    y = data[&#39;quality&#39;]<br><br>    # Split data into train and test sets<br>    X_train, X_test, y_train, y_test = train_test_split(<br>        X,<br>        y,<br>        test_size=0.2,<br>        random_state=42<br>    )<br>    return X_train, X_test, y_train, y_test<br><br>def fit_model(X_train, y_train, k = 5):<br>    # Implement KNN classifier<br>    knn = KNeighborsClassifier(n_neighbors=k)<br>    knn.fit(X_train, y_train)<br><br>    # Predict on the train set<br>    train_preds = knn.predict(X_train)<br><br>    # Calculate and return accuracy on train set<br>    train_accuracy = accuracy_score(y_train, train_preds)<br>    return train_accuracy, knn<br><br><br>def test_model(model, X_test, y_test):<br>    # Predict on the test set<br>    test_preds = model.predict(X_test)<br><br>    # Calculate and return accuracy on test set<br>    test_accuracy = accuracy_score(y_test, test_preds)<br>    return test_accuracy<br></pre><p><strong>Results:</strong><br>With a static k-value of 15, the model yields:</p><ul><li><strong>Test Accuracy:</strong> 48.44%</li></ul><p>The next step is to find the optimum k-value that yields the best accuracy on the training data.</p><h3>Optimizing KNN: Fine-Tuning Your Model</h3><h4>Enhanced Accuracy with GridSearchCV</h4><p>Employing GridSearchCV to find the best hyperparameter k-value resulted in a noticeable accuracy surge, hitting 50%. Optimizing the number of neighbors and exploring distance metrics were pivotal in this improvement.</p><p><strong>Results:</strong><br>With an optimized k-value of 19, the model yields:</p><ul><li><strong>Test Accuracy:</strong> 50.94%</li></ul><pre>def find_best_k_with_grid_search(X_train, y_train, X_test, y_test, param_grid):<br>    # Create a KNN classifier<br>    knn = KNeighborsClassifier()<br><br>    # Perform GridSearchCV<br>    grid_search = GridSearchCV(knn, param_grid, cv=5, scoring=&#39;accuracy&#39;)<br>    grid_search.fit(X_train, y_train)<br><br>    # Get the best parameter<br>    best_k = grid_search.best_params_[&#39;n_neighbors&#39;]<br><br>    # Fit model with best k on entire training set<br>    best_knn = KNeighborsClassifier(n_neighbors=best_k)<br>    best_knn.fit(X_train, y_train)<br><br>    # Calculate accuracy on train and test set<br>    train_accuracy = best_knn.score(X_train, y_train)<br>    test_accuracy = best_knn.score(X_test, y_test)<br>    <br>    return grid_search.best_params_, train_accuracy, test_accuracy<br><br><br># Assuming you have X_train, y_train variables<br>max_k=50<br><br># Define a grid of hyperparameters<br>parameters = {&#39;n_neighbors&#39;: range(2, max_k + 1)}<br><br>best_params, train_accuracy, test_accuracy = find_best_k_with_grid_search(X_train, y_train, X_test, y_test, parameters)<br>print(f&quot;Best k: {best_params[&#39;n_neighbors&#39;]}&quot;)<br>print(f&quot;Train Accuracy with Best k: {train_accuracy*100:.2f}%&quot;)<br>print(f&quot;Test Accuracy with Best k: {test_accuracy*100:.2f}%&quot;)</pre><h4>Weighing Distance for Precision</h4><p>By incorporating distance-based weighted averaging within GridSearchCV, the model’s accuracy jumped to nearly 51.56%. Considering the proximity of neighbors in the prediction significantly contributed to this progress.</p><p>We added both distance and uniform mode in the parameters to find the best k-value.</p><pre>parameters = {<br>    &quot;n_neighbors&quot;: range(2, max_k + 1),<br>    &quot;weights&quot;: [&quot;uniform&quot;, &quot;distance&quot;]<br>}</pre><p><strong>Results:</strong><br>With an optimized k-value of 43, and using weighted distance, the model yields:</p><ul><li><strong>Test Accuracy:</strong> 51.56%</li></ul><h4>Ensemble Modeling with Bagging</h4><p>Implementing Bagging with KNN led to a substantial leap in accuracy, reaching around 60.31%. Combining multiple KNN models through Bagging brought more robust predictions.</p><p><strong>Results:</strong><br>With a bagging ensemble model with 100 estimators, each randomly having 0.3 of the data.</p><ul><li><strong>Test Accuracy:</strong> 60.31%</li></ul><pre>def calculate_bagged_knn(X_train, y_train, X_test, y_test, best_k, best_weights):<br>    # Create a KNeighborsClassifier with best parameters<br>    knn = KNeighborsClassifier(n_neighbors=best_k, weights=best_weights)<br>    <br>    # Create BaggingClassifier with KNeighborsClassifier as base estimator<br>    bagged_knn = BaggingClassifier(estimator=knn, n_estimators=100, max_samples=0.3)<br>    <br>    # Fit the BaggingClassifier on the training data<br>    bagged_knn.fit(X_train, y_train)<br>    <br>    # Calculate training and test accuracies<br>    train_accuracy = bagged_knn.score(X_train, y_train)<br>    test_accuracy = bagged_knn.score(X_test, y_test)<br><br>    return train_accuracy, test_accuracy</pre><p>The complete code is accessible on GitHub.</p><h3>Pros and Cons of the kNN Algorithm</h3><p>K-Nearest Neighbors (KNN) brings forth advantages and limitations, offering interpretability and adaptability while grappling with computational demands and challenges in high-dimensional spaces.</p><h4>Advantages of KNN</h4><ol><li><strong>Interpretable and Fast Development:</strong> <em>KNN offers interpretability, allowing users to comprehend its functioning. Its simplicity facilitates the rapid development of models without the complexity of more advanced techniques.</em></li><li><strong>Adaptable to New Data:</strong> <em>It easily accommodates new data points without retraining, adjusting its predictions based on new examples added to the dataset.</em></li><li><strong>Few Hyperparameters:</strong> <em>Requires minimal parameter tuning — mainly ‘k’ and choice of distance metric — simplifying the training process.</em></li><li><strong>Robustness to Noisy Data:</strong> <em>Demonstrates resilience to noisy training data, aiding in effective classification, especially with a large dataset.</em></li><li><strong>Robustness to Large Training Data:</strong> <em>Can be more effective with larger training datasets, leveraging the abundance of information for predictions.</em></li></ol><h4>Drawbacks</h4><ol><li><strong>Computationally Intensive and Resource-Heavy:</strong> <em>As a lazy algorithm, KNN requires significant computing power and storage due to storing all data points, making it time and resource-consuming.</em></li><li><strong>Curse of Dimensionality:</strong> <em>Faces challenges with high-dimensional data, struggling to properly classify data points in higher dimensions, potentially leading to less accurate predictions.</em></li><li><strong>Needs Optimal ‘k’ Selection:</strong> <em>The choice of ‘k’ can significantly impact performance, requiring careful selection and optimization, which might be complex at times.</em></li><li><strong>Slower Performance with Increased Data:</strong> <em>The algorithm’s efficiency decreases notably as the dataset size or number of predictors/independent variables grows, affecting its speed.</em></li></ol><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*PKKvTLIJGsneTxzXl6163Q.jpeg" /><figcaption>Dall-E generated image with the following concept: Abstract machine learning using proximity-based algorithms</figcaption></figure><h3>Wrapping Up: Leveraging KNN in Python ML</h3><p>In this comprehensive exploration of K-Nearest Neighbors (KNN) in Python, we delved into the algorithm’s fundamentals, its pivotal components, and practical implementation aspects.</p><p>We’ve reviewed:</p><p><strong>Algorithm Insights:</strong> <em>Understanding how KNN classifies based on proximity to neighbors.</em><br><strong>Significance of K-Value:</strong> <em>Recognizing the impact of k-value on model performance and the trade-off between bias and variance.</em><br><strong>Distance Metrics Importance:</strong> <em>Appreciating the role of distance metrics in shaping decision boundaries and influencing predictions.</em><br><strong>KNN Implementation from Scratch:</strong> <em>Crafting KNN code from the ground up, enhancing comprehension of its inner workings.</em><br><strong>Fine-Tuning on Wine Quality Dataset:</strong> <em>Iteratively optimizing KNN on the wine quality dataset to elevate its predictive capacity.</em><br><strong>Advantages and Disadvantages:</strong> <em>Weighing the pros and cons to comprehend where KNN excels and where it faces limitations.</em></p><p>Hope you enjoyed the KNN pattern exploration.</p><p>Happy training! 👩‍💻</p><h4>Explore the GitHub Repo 🎉</h4><p><a href="https://github.com/AmirLavasani/retro-machine-learning">GitHub - AmirLavasani/retro-machine-learning: ⏱ Original implementations from scratch of timeless classic machine learning algorithms such as KNN, SVM, PCA, Decision Trees, K-means, and more.</a></p><h4>Resources</h4><ol><li><a href="https://www.microsoft.com/en-us/research/uploads/prod/2006/01/Bishop-Pattern-Recognition-and-Machine-Learning-2006.pdf">Pattern Recognition and Machine Learning by </a><a href="https://www.google.com/search?sa=X&amp;sca_esv=f8ea33c309cd8c22&amp;cs=1&amp;biw=1536&amp;bih=773&amp;q=Christopher+Bishop&amp;si=AKbGX_qWtsfHufXsq_1jeDkJp50FstNngDxsch3EVTUjn7imcOWl_fEAW8VZl36pb2llr2C-oBjsIauyROHK_ncRMSOvja9M_dfcf97MY_fkQ9HSNva8Qfnr_GeHLnbpcqyVyp48V21kd9B4JcFZBBKXeGDOnitxfD662c9TzKGh0M56uhEjajH_NN1yftkflEJwXYr0hrJa7_6BUT0zCTC1UOpobjNciQ%3D%3D&amp;ved=2ahUKEwj4uMDvgpaEAxXK8gIHHQeDBykQmxMoAHoECCIQAg">Christopher Bishop</a> <a href="https://www.microsoft.com/en-us/research/uploads/prod/2006/01/Bishop-Pattern-Recognition-and-Machine-Learning-2006.pdf">(Book)</a></li><li><a href="https://realpython.com/knn-python/">realpython The k-Nearest Neighbors (kNN) Algorithm in Python</a></li><li><a href="https://scikit-learn.org/stable/auto_examples/neighbors/plot_classification.html#sphx-glr-auto-examples-neighbors-plot-classification-py">scikit-learn Nearest Neighbors Classification</a></li><li><a href="https://www.ibm.com/topics/knn">IBM K-Nearest Neighbors Algorithm</a></li><li><a href="https://towardsdatascience.com/machine-learning-basics-with-the-k-nearest-neighbors-algorithm-6a6e71d01761">Machine Learning Basics with the K-Nearest Neighbors Algorithm</a></li><li><a href="https://medium.com/swlh/k-nearest-neighbor-ca2593d7a3c4">Medium K-Nearest Neighbor</a></li><li><a href="https://www.pinecone.io/learn/k-nearest-neighbor/">K-Nearest Neighbor (KNN) Explained</a></li><li><a href="https://www.analyticsvidhya.com/blog/2018/03/introduction-k-neighbours-algorithm-clustering/#:~:text=The%20K%2DNearest%20Neighbors%20(KNN)%20algorithm%20is%20a%20popular,training%20dataset%20as%20a%20reference">A Complete Guide to K-Nearest Neighbors</a></li></ol><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=a06fbfaaf80a" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Design Patterns in Python: Strategy]]></title>
            <link>https://medium.com/@amirm.lavasani/design-patterns-in-python-strategy-7b14f1c4c162?source=rss-2e98894ce1bf------2</link>
            <guid isPermaLink="false">https://medium.com/p/7b14f1c4c162</guid>
            <category><![CDATA[software-architecture]]></category>
            <category><![CDATA[programming]]></category>
            <category><![CDATA[design-patterns]]></category>
            <category><![CDATA[python]]></category>
            <category><![CDATA[strategy]]></category>
            <dc:creator><![CDATA[Amir Lavasani]]></dc:creator>
            <pubDate>Tue, 30 Jan 2024 07:04:54 GMT</pubDate>
            <atom:updated>2024-02-14T09:10:12.542Z</atom:updated>
            <content:encoded><![CDATA[<h4>TUTORIAL SERIES</h4><h4>Dynamic Algorithm Switching</h4><blockquote>Have you encountered recurring coding challenges? Imagine having a toolbox of tried-and-true solutions readily available. That’s precisely what design patterns provide. In <a href="https://medium.com/@amirm.lavasani/design-patterns-in-python-a-series-f502b7804ae5">this series</a>, we’ll explore what these patterns are and how they can elevate your coding skills.</blockquote><p><a href="https://medium.com/@amirm.lavasani/design-patterns-in-python-a-series-f502b7804ae5">Design Patterns in Python: A Series</a></p><h3>Understanding the Strategy Pattern</h3><h4>What is the Strategy Design Pattern?</h4><p>The Strategy Design Pattern is a behavioral design paradigm that encapsulates a family of interchangeable algorithms, allowing dynamic selection by a client class.</p><p>This decouples algorithmic implementation from the client, promoting flexibility and ease of modification without altering the client’s structure.</p><h4>When to Use the Strategy Pattern:</h4><p>Consider employing the Strategy Pattern for the following cases:</p><ol><li><strong>Dynamic Algorithm Switching: </strong><em>We Need multiple variations of an algorithm within an object with the ability to switch during runtime.</em></li><li><strong>Behavioral Differences in Similar Classes:</strong> <em>Dealing with numerous classes that share similarities but differ in behavior execution.</em></li><li><strong>Business Logic Isolation:</strong><em> Separating business logic from algorithm implementation details.</em></li><li><strong>Simplify Massive Conditional Statements:</strong> <em>Your class has an extensive conditional statement handling different algorithm variants.</em></li></ol><h4>Practical Example: A Trading Strategy System</h4><p>we’ll implement a trading strategy system in Python using the Strategy Design Pattern. We aim to demonstrate the adaptability and flexibility of the pattern by encapsulating different trading strategies, such as Moving Average and Mean Reversion, as interchangeable components.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*otkWGB7E4-Yy2QEXU_2cpg.jpeg" /><figcaption>Dall-E generated image with the following concept: Abstract chess pieces in motion, each representing a strategy</figcaption></figure><h3>Terminology and Key Components</h3><p>To grasp the essence of the Strategy Design Pattern, let’s delve into its key components:</p><ol><li><strong>Context:</strong> <em>Maintains a reference to one of the concrete strategies and communicates with this object only via the strategy interface.</em></li><li><strong>Strategy Interface:</strong> <em>Common to all concrete strategies, declares a method the context uses to execute a strategy.</em></li><li><strong>Concrete Strategies:</strong> Implement different variations of an algorithm the context uses.</li></ol><figure><img alt="" src="https://cdn-images-1.medium.com/max/440/1*3K6LTy033we1GnDk_vvDTw.png" /><figcaption>Strategy design pattern structure diagram. Image from <a href="https://refactoring.guru/design-patterns/strategy">refactoring.guru</a></figcaption></figure><h3>Strategy Pattern Implementation in Python</h3><h4>Step 1: Strategy Interface</h4><p>Define an abstract class Strategy that declares a method execute_strategy common to all concrete strategies.</p><pre>from abc import ABC, abstractmethod<br><br># Step 1: Create the Strategy Interface<br>class Strategy(ABC):<br>    @abstractmethod<br>    def execute_strategy(self):<br>        pass</pre><h4>Step 2: Concrete Strategies</h4><p>Implement concrete strategy classes ConcreteStrategyA and ConcreteStrategyB that provide specific algorithm variations.</p><pre># Step 2: Create Concrete Strategies<br>class ConcreteStrategyA(Strategy):<br>    def execute_strategy(self):<br>        return &quot;Executing Strategy A&quot;<br><br>class ConcreteStrategyB(Strategy):<br>    def execute_strategy(self):<br>        return &quot;Executing Strategy B&quot;</pre><h4>Step 3: Context</h4><p>Develop a Context class that maintains a reference to one of the concrete strategies and provides a method to execute the strategy.</p><pre># Step 3: Create the Context<br>class Context:<br>    def __init__(self, strategy):<br>        # Context maintains a reference to one of the concrete strategies<br>        self._strategy = strategy<br><br>    def set_strategy(self, strategy):<br>        # Exposes a setter to replace the strategy <br>        # associated with the context at runtime<br>        self._strategy = strategy<br><br>    def execute_strategy(self):<br>        # Context calls the execution method on the linked strategy object<br>        return self._strategy.execute_strategy()</pre><h4>Client</h4><pre># Main Section to Showcase Usage<br>if __name__ == &quot;__main__&quot;:<br>    # Create concrete strategy objects<br>    strategy_a = ConcreteStrategyA()<br>    strategy_b = ConcreteStrategyB()<br><br>    # Create context with a default strategy<br>    context = Context(strategy_a)<br><br>    # Execute the default strategy<br>    print(context.execute_strategy())  # Output: Executing Strategy A<br><br>    # Switch to a different strategy at runtime<br>    context.set_strategy(strategy_b)<br>    print(context.execute_strategy())  # Output: Executing Strategy B</pre><h4>GitHub Repo 🎉</h4><p>Explore all code examples and design pattern implementations on GitHub!</p><p><a href="https://github.com/AmirLavasani/python-design-patterns">GitHub - AmirLavasani/python-design-patterns: Explore design patterns using Python with code examples to solve common software challenges.</a></p><h3>Practical Example: A Trading Strategy System</h3><p>In this section, we implement a dynamic trading strategy system in Python, showcasing the capability to switch strategies seamlessly at runtime.</p><h4>Step 1: Create the Strategy Interface</h4><pre># Step 1: Create the Strategy Interface<br>class TradingStrategy(ABC):<br>    @abstractmethod<br>    def execute_trade(self, data):<br>        pass</pre><h4>Step 2: Create Concrete Strategies</h4><pre># Step 2: Create Concrete Strategies<br>class MovingAverageStrategy(TradingStrategy):<br>    def execute_trade(self, data):<br>        # Calculate Moving Average (Simple example for illustration)<br>        window_size = 3  # Adjust as needed<br>        moving_average = sum(data[-window_size:]) / window_size<br>        return f&quot;Executing Moving Average Trading Strategy. Moving Average: {moving_average:.2f}&quot;<br><br>class MeanReversionStrategy(TradingStrategy):<br>    def execute_trade(self, data):<br>        # Calculate Mean Reversion (Simple example for illustration)<br>        mean_value = sum(data) / len(data)<br>        deviation = data[-1] - mean_value<br>        return f&quot;Executing Mean Reversion Trading Strategy. Deviation from Mean: {deviation:.2f}&quot;</pre><h4>Step 3: Create the Context</h4><pre># Step 3: Create the Context<br>class TradingContext:<br>    def __init__(self, strategy):<br>        self._strategy = strategy<br><br>    def set_strategy(self, strategy):<br>        self._strategy = strategy<br><br>    def execute_trade(self, data):<br>        return self._strategy.execute_trade(data)</pre><h4>Client</h4><pre># Main Section to Showcase Usage<br>if __name__ == &quot;__main__&quot;:<br>    # Sample data for trading<br>    trading_data = [50, 55, 45, 60, 50]<br><br>    # Create concrete strategy objects<br>    moving_average_strategy = MovingAverageStrategy()<br>    mean_reversion_strategy = MeanReversionStrategy()<br><br>    # Create context with a default strategy<br>    trading_context = TradingContext(moving_average_strategy)<br><br>    # Execute the default strategy<br>    result = trading_context.execute_trade(trading_data)<br>    print(result)  # Output: Executing Moving Average Trading Strategy. Moving Average: 51.67<br><br>    # Switch to a different strategy at runtime<br>    trading_context.set_strategy(mean_reversion_strategy)<br>    <br>    # Execute the updated strategy<br>    result = trading_context.execute_trade(trading_data)<br>    print(result)  # Output: Executing Mean Reversion Trading Strategy. Deviation from Mean: -1.00</pre><h3>Real-World Use Cases for Strategy Pattern</h3><ol><li><strong>Python’s </strong><strong>sort function: </strong><em>The </em><em>sort function in Python allows users to pass a custom comparison function, showcasing the Strategy Pattern.</em></li><li><strong>Redux State Management in React:</strong> <em>In React applications using Redux, the middleware pattern employs the Strategy Pattern for handling asynchronous actions.</em></li><li><strong>Scikit-learn Machine Learning Library in Python:</strong> <em>Scikit-learn’s preprocessing module utilizes the Strategy Pattern for handling missing data.</em></li><li><strong>Unity Game Engine:</strong> <em>Unity’s input system employs the Strategy Pattern for defining various input handling strategies.</em></li><li><strong>TensorFlow Machine Learning Library:</strong> <em>In TensorFlow, optimizers like stochastic gradient descent use the Strategy Pattern for defining different optimization strategies.</em></li></ol><h3>Best Practices and Considerations</h3><p>When employing the Strategy Design Pattern, it’s essential to be mindful of both its advantages and potential considerations:</p><h4>Pros</h4><ol><li><strong>Runtime Algorithm Swap:</strong> <em>The ability to switch algorithms dynamically at runtime enhances adaptability and flexibility.</em></li><li><strong>Implementation Isolation:</strong> <em>The pattern isolates the implementation details of an algorithm, promoting cleaner and more maintainable code.</em></li><li><strong>Composition Over Inheritance:</strong> <em>It allows replacing inheritance with composition, emphasizing a more flexible design approach.</em></li></ol><h4>Cons</h4><ol><li><strong>Programmatic Overhead:</strong> <em>For a limited number of rarely changing algorithms, the introduction of extra classes and interfaces may lead to unnecessary complexity.</em></li><li><strong>Client Awareness:</strong> <em>Clients need awareness of the differences between strategies to make informed selections, introducing potential cognitive load.</em></li><li><strong>Functional Alternatives:</strong> <em>Some modern programming languages with functional support offer alternatives, implementing different algorithm versions without additional class and interface overhead.</em></li></ol><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*IHjsaGXiKH7bZhVBCJaUGg.jpeg" /><figcaption>Dall-E generated image with the following concept: AI entity that runs the world trading</figcaption></figure><h3>Strategy Pattern’s Relations with Other Patterns</h3><p>The Strategy Pattern shares structural similarities with other patterns such as Bridge, State, and to some extent, Adapter.</p><p>While they all utilize composition for delegating work to other objects, each pattern addresses distinct problems.</p><h4>Command Pattern</h4><p>Both Command and Strategy can be used to parameterize an object with an action.</p><p><strong>Command:</strong> <em>converts any operation into an object, allowing deferred execution, queuing, and remote command handling.</em></p><p><strong>Strategy:</strong><em> describes different ways of doing the same thing, enabling the swapping of algorithms within a single context class.</em></p><h4>Decorator Pattern</h4><p>Both Decorator and Strategy allow altering an object’s behavior.</p><p><strong>Decorator:</strong> <em>changes the outer layer or “skin” of an object, enhancing its functionalities.</em></p><p><strong>Strategy:</strong> <em>focuses on changing the internal workings or “guts” of an object by providing different algorithms.</em></p><h4>Template Method Pattern</h4><p>Both Template Method and Strategy are based on altering parts of an algorithm.</p><p><strong>Template Method:</strong> <em>relies on inheritance to extend and alter algorithm parts in subclasses (class level).</em></p><p><strong>Strategy:</strong> <em>relies on composition to switch behaviors at runtime (object level).</em></p><h4>State Pattern</h4><p>The State pattern can be considered an extension of Strategy, both based on composition.</p><p><strong>State:</strong> <em>allows dependencies between concrete states, enabling them to alter the context’s state at will.</em></p><p><strong>Strategy:</strong> <em>makes objects independent and unaware of each other.</em></p><h3>Conclusion</h3><p>In wrapping up our exploration of the Strategy Pattern in Python, we’ve uncovered a pattern that brings dynamic algorithmic switches to your code. The trio of Strategy Interface, Concrete Strategies, and Context forms a pattern that allows one to change algorithms on the fly.</p><p>We covered the pattern&#39;s main components, pros and cons, and its relation and comparison to other patterns. We have also implemented a simple trading system that changes algorithms in real time to show the power of the strategy pattern.</p><p>Happy coding! 👩‍💻</p><h3>Next on the Series 🚀</h3><p><a href="https://medium.com/@amirm.lavasani/design-patterns-in-python-observer-ac50bbf861b5">Design Patterns in Python: Observer</a></p><h3>Read More 📜</h3><ul><li><a href="https://medium.com/@amirm.lavasani/design-patterns-in-python-memento-5b8f94d84bc3">Design Patterns in Python: Memento</a></li><li><a href="https://medium.com/@amirm.lavasani/design-patterns-in-python-mediator-ca42c2caca52">Design Patterns in Python: Mediator</a></li></ul><h3>The Series 🧭</h3><p><a href="https://medium.com/@amirm.lavasani/design-patterns-in-python-a-series-f502b7804ae5">Design Patterns in Python: A Series</a></p><h3>References</h3><ol><li><a href="https://www.goodreads.com/en/book/show/85009">Design Patterns: Elements of Reusable Object-Oriented Software</a> (Book)</li><li><a href="https://refactoring.guru/design-patterns/strategy">refactoring.guru Strategy</a></li><li><a href="https://www.goodreads.com/en/book/show/58128">Head First Design Patterns</a> (Book)</li><li><a href="https://www.freecodecamp.org/news/a-beginners-guide-to-the-strategy-design-pattern/">A Beginner’s Guide to the Strategy Design Pattern</a></li><li><a href="https://www.digitalocean.com/community/tutorials/strategy-design-pattern-in-java-example-tutorial">Strategy Design Pattern in Java — Example Tutorial</a></li><li><a href="https://sourcemaking.com/design_patterns/strategy">sourcemaking Strategy Design Pattern</a></li></ol><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=7b14f1c4c162" width="1" height="1" alt="">]]></content:encoded>
        </item>
    </channel>
</rss>