<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Rajesh Vemulakonda</title>
    <description>The latest articles on DEV Community by Rajesh Vemulakonda (@vemulakonda559).</description>
    <link>https://dev.to/vemulakonda559</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4028422%2F81df2cc6-34e8-4bd9-add9-17dac778dd32.png</url>
      <title>DEV Community: Rajesh Vemulakonda</title>
      <link>https://dev.to/vemulakonda559</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/vemulakonda559"/>
    <language>en</language>
    <item>
      <title>Duck Typing in Python: Powerful Feature or Hidden Trap?</title>
      <dc:creator>Rajesh Vemulakonda</dc:creator>
      <pubDate>Tue, 04 Aug 2026 09:32:01 +0000</pubDate>
      <link>https://dev.to/vemulakonda559/duck-typing-in-python-powerful-feature-or-hidden-trap-j4i</link>
      <guid>https://dev.to/vemulakonda559/duck-typing-in-python-powerful-feature-or-hidden-trap-j4i</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Python often follows a simple idea:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If an object provides the behavior we need, why should we care what type it is?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Consider this function:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;make_sound&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;animal&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;animal&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;speak&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It doesn't check whether &lt;code&gt;animal&lt;/code&gt; inherits from a particular class. It simply expects the object to provide &lt;code&gt;speak()&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;So these unrelated classes work perfectly:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Dog&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;speak&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Woof&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Cat&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;speak&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Meow&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nf"&gt;make_sound&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Dog&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;span class="nf"&gt;make_sound&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Cat&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This flexibility is one of Python's strengths and is commonly known as &lt;strong&gt;duck typing&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;But there's another side to it.&lt;/p&gt;

&lt;p&gt;What happens if we pass an object that doesn't provide the expected behavior?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Fish&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;pass&lt;/span&gt;


&lt;span class="nf"&gt;make_sound&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Fish&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The flexibility suddenly becomes a runtime error:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;AttributeError: 'Fish' object has no attribute 'speak'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That raises an interesting question:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Is duck typing one of Python's most powerful features, or can that same flexibility become a hidden trap?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The answer is &lt;strong&gt;both&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;In this article, we'll explore why duck typing makes Python code flexible and extensible, where it can introduce runtime failures, and how to decide when that flexibility is worth using.&lt;/p&gt;




&lt;h2&gt;
  
  
  What Is Duck Typing?
&lt;/h2&gt;

&lt;p&gt;Duck typing is an approach where an object's suitability is determined by the &lt;strong&gt;behavior it provides&lt;/strong&gt;, rather than by its class or inheritance hierarchy.&lt;/p&gt;

&lt;p&gt;The idea comes from the well-known saying:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If it walks like a duck and quacks like a duck, then it can be treated as a duck.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In Python terms, instead of asking:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Is this object a particular type?
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;we often care more about:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Does this object support the operation I need?
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Our &lt;code&gt;make_sound()&lt;/code&gt; function follows exactly this idea: it doesn't require the object to inherit from a particular base class. It only expects the object to provide a compatible &lt;code&gt;speak()&lt;/code&gt; method.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Robot&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;speak&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Beep&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


&lt;span class="nf"&gt;make_sound&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Robot&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Beep
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;Robot&lt;/code&gt; doesn't share a parent class with &lt;code&gt;Dog&lt;/code&gt; or &lt;code&gt;Cat&lt;/code&gt;, but that doesn't matter. It provides the expected behavior, so it works.&lt;/p&gt;

&lt;p&gt;That's the central idea behind duck typing:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;What an object can do matters more than what type it is.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This allows Python code to work with different objects without forcing them into a common inheritance hierarchy.&lt;/p&gt;

&lt;p&gt;That flexibility is exactly what makes duck typing powerful.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why Duck Typing Is Powerful
&lt;/h2&gt;

&lt;p&gt;Duck typing allows functions to work with different objects without requiring them to share a common base class.&lt;/p&gt;

&lt;p&gt;Consider a simple exporter:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;PDFExporter&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;export&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Exporting PDF&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;CSVExporter&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;export&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Exporting CSV&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A generic function can work with either:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;export_data&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;exporter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;exporter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;export&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Usage:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nf"&gt;export_data&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;PDFExporter&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;export_data&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;CSVExporter&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;export_data()&lt;/code&gt; doesn't need to know the concrete type of the exporter. It only expects an object that provides a compatible &lt;code&gt;export()&lt;/code&gt; method.&lt;/p&gt;

&lt;h3&gt;
  
  
  Less Coupling
&lt;/h3&gt;

&lt;p&gt;Because the function depends on behavior rather than a specific class hierarchy, the objects remain loosely coupled.&lt;/p&gt;

&lt;p&gt;There is no requirement such as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;PDFExporter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Exporter&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="bp"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;just to make &lt;code&gt;PDFExporter&lt;/code&gt; usable by &lt;code&gt;export_data()&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Easy Extension
&lt;/h3&gt;

&lt;p&gt;Suppose we later need JSON support:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;JSONExporter&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;export&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Exporting JSON&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It immediately works with the existing function:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nf"&gt;export_data&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;JSONExporter&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No changes to &lt;code&gt;export_data()&lt;/code&gt; are required. We extend the system by adding new behavior rather than modifying code that already works.&lt;/p&gt;

&lt;p&gt;This also aligns naturally with the &lt;strong&gt;Open/Closed Principle (OCP)&lt;/strong&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Software entities should be open for extension but closed for modification.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Duck typing can help support this principle by allowing new compatible objects to work with existing code without requiring changes to that code.&lt;/p&gt;

&lt;p&gt;For a deeper look at this idea, see my companion article:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://dev.to/vemulakonda559/stop-editing-working-code-understanding-the-openclosed-principle-in-python-502b"&gt;Stop Editing Working Code: Understanding the Open/Closed Principle in Python&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Together, loose coupling and easy extension make duck typing a powerful design tool.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If an object provides the expected behavior, it can participate.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;But that flexibility comes with a trade-off.&lt;/p&gt;

&lt;p&gt;What happens when an object &lt;em&gt;doesn't&lt;/em&gt; provide the behavior we expect?&lt;/p&gt;

&lt;p&gt;That's where duck typing can become a hidden trap.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Hidden Trap: Errors Appear at Runtime
&lt;/h2&gt;

&lt;p&gt;That trade-off becomes clear when an object doesn't provide the behavior the code expects.&lt;/p&gt;

&lt;p&gt;Consider our exporter:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;export_data&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;exporter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;exporter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;export&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The function assumes that the object it receives provides an &lt;code&gt;export()&lt;/code&gt; method.&lt;/p&gt;

&lt;p&gt;Now suppose we pass an incompatible object:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Logger&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nf"&gt;export_data&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Logger&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;Logger&lt;/code&gt; doesn't provide &lt;code&gt;export()&lt;/code&gt;, so the program fails at runtime:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;AttributeError: 'Logger' object has no attribute 'export'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's one of the risks of duck typing.&lt;/p&gt;

&lt;p&gt;The function can be called with the object without requiring it to belong to a particular class hierarchy. But that also means incompatibility may not become apparent until the expected operation is actually performed.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Problem Grows in Larger Systems
&lt;/h3&gt;

&lt;p&gt;In a small example, the mistake is obvious.&lt;/p&gt;

&lt;p&gt;In a larger application, an incompatible object might travel through several functions or components before the missing behavior is finally used.&lt;/p&gt;

&lt;p&gt;The error then appears far from where the wrong object originally entered the system, making the problem harder to trace.&lt;/p&gt;

&lt;p&gt;Duck typing therefore gives us freedom, but also places responsibility on developers to understand the behavioral expectations of their code.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Flexibility is powerful when the expected behavior is clear. It becomes risky when that contract is only implicit.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;And a missing method isn't the only possible problem.&lt;/p&gt;

&lt;p&gt;Sometimes an object provides the expected method name, yet its behavior is still incompatible.&lt;/p&gt;

&lt;p&gt;That's an even subtler trap.&lt;/p&gt;




&lt;h2&gt;
  
  
  When Behavior Looks Compatible but Isn't
&lt;/h2&gt;

&lt;p&gt;Duck typing is not only about whether a method exists.&lt;/p&gt;

&lt;p&gt;The method must also be compatible with how the caller expects to use it.&lt;/p&gt;

&lt;p&gt;Consider our exporter again:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;export_data&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;exporter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;exporter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;export&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now suppose we create this class:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ReportExporter&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;export&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Exporting report&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;At first glance, &lt;code&gt;ReportExporter&lt;/code&gt; appears compatible because it provides an &lt;code&gt;export()&lt;/code&gt; method.&lt;/p&gt;

&lt;p&gt;But this call:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nf"&gt;export_data&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;ReportExporter&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;fails:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;TypeError: ReportExporter.export() takes 1 positional argument but 2 were given
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The method exists, but its signature doesn't match what &lt;code&gt;export_data()&lt;/code&gt; expects.&lt;/p&gt;

&lt;h3&gt;
  
  
  Same Method Name, Different Meaning
&lt;/h3&gt;

&lt;p&gt;The problem can be even more subtle when the signature matches but the behavior doesn't.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Database&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;export&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Removing exported records from database&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Technically, this object provides:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nf"&gt;export&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But its behavior may violate what the caller expects from an exporter.&lt;/p&gt;

&lt;p&gt;This highlights an important point:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Duck typing depends on a behavioral contract, not just matching method names.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That contract may include the method name, accepted arguments, return value, side effects, and expected meaning of the operation.&lt;/p&gt;

&lt;p&gt;When those expectations remain implicit, duck typing can make incorrect objects appear compatible until something goes wrong.&lt;/p&gt;

&lt;p&gt;So how can we keep the flexibility of duck typing while making those expectations clearer?&lt;/p&gt;

&lt;p&gt;That's where safer design practices can help.&lt;/p&gt;




&lt;h2&gt;
  
  
  Making Duck-Typed Code Safer
&lt;/h2&gt;

&lt;p&gt;Duck typing doesn't have to mean giving up clarity or safety.&lt;/p&gt;

&lt;p&gt;The key is to make the expected behavior as clear as possible.&lt;/p&gt;

&lt;h3&gt;
  
  
  Use Clear Behavioral Expectations
&lt;/h3&gt;

&lt;p&gt;A function should make its requirements easy to understand:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;export_data&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;exporter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;exporter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;export&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, the expectation is simple: &lt;code&gt;exporter&lt;/code&gt; must provide an &lt;code&gt;export()&lt;/code&gt; method that accepts &lt;code&gt;data&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Good naming and documentation can make such contracts easier for developers to understand.&lt;/p&gt;

&lt;h3&gt;
  
  
  Make Expectations Explicit With Type Hints
&lt;/h3&gt;

&lt;p&gt;Type hints can make expectations more explicit and allow static type checkers to catch certain mistakes before runtime.&lt;/p&gt;

&lt;p&gt;For example, Python's &lt;code&gt;typing.Protocol&lt;/code&gt; can describe the behavior an object is expected to provide without requiring inheritance from a particular base class.&lt;/p&gt;

&lt;p&gt;Conceptually, we can express:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Any object that provides:

export(data)

can be treated as an exporter.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This preserves the flexibility of duck typing while making the expected interface clearer.&lt;/p&gt;

&lt;p&gt;We'll explore &lt;code&gt;Protocol&lt;/code&gt; in detail in a separate article.&lt;/p&gt;

&lt;h3&gt;
  
  
  Test the Expected Behavior
&lt;/h3&gt;

&lt;p&gt;Tests are especially valuable when code relies on behavioral contracts.&lt;/p&gt;

&lt;p&gt;If several objects are expected to satisfy the same behavioral contract, test each implementation against those expectations.&lt;/p&gt;

&lt;p&gt;This helps catch problems such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Missing methods&lt;/li&gt;
&lt;li&gt;Incompatible method signatures&lt;/li&gt;
&lt;li&gt;Unexpected return values&lt;/li&gt;
&lt;li&gt;Incorrect behavior&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Duck typing works best when flexibility is combined with clear expectations and good testing.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The goal isn't to remove duck typing's flexibility, but to make its implicit contracts easier to understand and verify.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  When Duck Typing Is a Good Choice
&lt;/h2&gt;

&lt;p&gt;Duck typing works particularly well when different objects naturally support the same behavior without needing a shared inheritance hierarchy.&lt;/p&gt;

&lt;h3&gt;
  
  
  When Behavior Matters More Than Type
&lt;/h3&gt;

&lt;p&gt;If a function only needs a specific capability, requiring a particular class may add unnecessary coupling.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;save&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;writer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;writer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The function doesn't need to know whether &lt;code&gt;writer&lt;/code&gt; is a file object, an in-memory buffer, or some other compatible object.&lt;/p&gt;

&lt;p&gt;It only needs:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nf"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This keeps the function flexible and focused on the behavior it actually requires.&lt;/p&gt;

&lt;h3&gt;
  
  
  When Working With Small, Clear Interfaces
&lt;/h3&gt;

&lt;p&gt;Duck typing is especially effective when the expected interface is simple and easy to understand.&lt;/p&gt;

&lt;p&gt;A requirement such as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Object must provide:

send(message)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;is easier to reason about than an object expected to provide many loosely defined methods.&lt;/p&gt;

&lt;p&gt;The smaller and clearer the behavioral contract, the easier duck typing is to use safely.&lt;/p&gt;

&lt;h3&gt;
  
  
  When Extensibility Matters
&lt;/h3&gt;

&lt;p&gt;Duck typing also works well when new implementations are likely to be added over time.&lt;/p&gt;

&lt;p&gt;If a new object provides the expected behavior, existing code can often work with it without modification.&lt;/p&gt;

&lt;p&gt;This makes duck typing a natural choice for extensible systems where flexibility is valuable and the expected behavioral contract remains clear.&lt;/p&gt;




&lt;p&gt;Duck typing is therefore a strong choice when:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The required behavior is small and clearly defined.&lt;/li&gt;
&lt;li&gt;Different types naturally provide the same operation.&lt;/li&gt;
&lt;li&gt;A shared inheritance hierarchy would add little value.&lt;/li&gt;
&lt;li&gt;Extensibility and loose coupling are important.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But flexibility isn't always the right priority.&lt;/p&gt;

&lt;p&gt;When behavioral expectations become larger, more complex, or harder to discover, a more explicit contract may be a better choice.&lt;/p&gt;




&lt;h2&gt;
  
  
  When to Prefer a More Explicit Contract
&lt;/h2&gt;

&lt;p&gt;Duck typing works well when the expected behavior is small and obvious.&lt;/p&gt;

&lt;p&gt;But as a system grows, those expectations can become harder to understand and maintain.&lt;/p&gt;

&lt;p&gt;Suppose a component expects an object to provide several operations:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;connect()
send(data)
receive()
close()
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With a simple duck-typed design, that contract may remain implicit in documentation, tests, or the assumptions made by the surrounding code.&lt;/p&gt;

&lt;p&gt;As the interface grows, developers may need a clearer way to understand what an object is expected to provide.&lt;/p&gt;

&lt;h3&gt;
  
  
  When Expectations Become Complex
&lt;/h3&gt;

&lt;p&gt;A more explicit contract can be useful when:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Several methods must work together.&lt;/li&gt;
&lt;li&gt;Method signatures and return types matter.&lt;/li&gt;
&lt;li&gt;Many developers work with the same interface.&lt;/li&gt;
&lt;li&gt;Incorrect implementations would be difficult to detect.&lt;/li&gt;
&lt;li&gt;Static type checking is important to the project.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The goal isn't to abandon duck typing.&lt;/p&gt;

&lt;p&gt;It's to make the expected behavior easier to discover and verify.&lt;/p&gt;

&lt;h3&gt;
  
  
  Python Gives Us Options
&lt;/h3&gt;

&lt;p&gt;Depending on the design, Python provides several ways to make contracts more explicit, including:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Abstract Base Classes&lt;/li&gt;
&lt;li&gt;Type hints&lt;/li&gt;
&lt;li&gt;&lt;code&gt;typing.Protocol&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Abstract base classes can define an explicit inheritance-based interface.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Protocol&lt;/code&gt; is particularly interesting because it can describe the expected behavior without requiring explicit inheritance, making it a natural companion to duck typing.&lt;/p&gt;

&lt;p&gt;We won't explore &lt;code&gt;Protocol&lt;/code&gt; in detail here, but it leads to an interesting question:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Can we keep the flexibility of duck typing while gaining stronger type checking and clearer contracts?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That's a topic worth exploring on its own.&lt;/p&gt;




&lt;p&gt;The important point is that neither approach is universally better.&lt;/p&gt;

&lt;p&gt;Duck typing offers flexibility and loose coupling.&lt;/p&gt;

&lt;p&gt;Explicit contracts offer clarity and stronger ways to express and check expectations.&lt;/p&gt;

&lt;p&gt;Good design comes from choosing the level of structure that fits the problem.&lt;/p&gt;




&lt;h2&gt;
  
  
  Key Takeaways
&lt;/h2&gt;

&lt;p&gt;Duck typing is one of Python's most flexible features, but that flexibility comes with responsibility.&lt;/p&gt;

&lt;p&gt;Here are the key ideas:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Duck typing focuses on behavior, not inheritance.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If an object provides the expected behavior, it can often be used regardless of its class hierarchy.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;It promotes flexibility and loose coupling.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Functions can work with different object types without requiring them to inherit from a common base class.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;The contract is often implicit.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;An object may appear compatible but still fail because of a missing method, an incompatible signature, or unexpected behavior.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Some compatibility problems surface only at runtime.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Without clearer contracts or static checking, incompatibilities may remain unnoticed until the relevant code executes.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Duck typing works best with small, clear interfaces.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The easier the expected behavior is to understand, the easier duck typing is to use effectively.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;More complex systems may benefit from explicit contracts.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Abstract base classes, type hints, and &lt;code&gt;Protocol&lt;/code&gt; can make behavioral expectations clearer when additional structure is useful.&lt;/p&gt;




&lt;p&gt;The central idea is simple:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Duck typing is powerful when its behavioral contract is clear. It becomes a hidden trap when that contract is misunderstood or left ambiguous.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;So, is duck typing in Python a powerful feature or a hidden trap?&lt;/p&gt;

&lt;p&gt;The answer is:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;It can be both.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Duck typing contributes to Python's flexibility. It allows different objects to work with the same code based on the behavior they provide, without forcing them into a common inheritance hierarchy.&lt;/p&gt;

&lt;p&gt;But that flexibility comes with a trade-off.&lt;/p&gt;

&lt;p&gt;When behavioral expectations are unclear, incompatible objects may fail only at runtime. And as those expectations become more complex, implicit contracts can become harder to understand and maintain.&lt;/p&gt;

&lt;p&gt;The goal, therefore, isn't to avoid duck typing or use it everywhere.&lt;/p&gt;

&lt;p&gt;It's to recognize when its flexibility helps and when additional structure would make the code clearer and safer.&lt;/p&gt;

&lt;p&gt;For small, well-understood behavioral contracts, duck typing can be elegant and powerful. For larger or more complex contracts, tools such as type hints, abstract base classes, and &lt;code&gt;Protocol&lt;/code&gt; can make expectations more explicit.&lt;/p&gt;

&lt;p&gt;Perhaps the best way to think about duck typing is:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Flexibility is a strength when the contract is clear. Without clarity, the same flexibility can become a liability.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;And that leads naturally to another question:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Can Python preserve the flexibility of duck typing while making behavioral contracts explicit and statically checkable?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That's where &lt;code&gt;typing.Protocol&lt;/code&gt; enters the picture.&lt;/p&gt;




</description>
      <category>python</category>
      <category>programming</category>
      <category>oop</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Does Polymorphism Always Require Inheritance? A Python Perspective</title>
      <dc:creator>Rajesh Vemulakonda</dc:creator>
      <pubDate>Mon, 20 Jul 2026 07:03:36 +0000</pubDate>
      <link>https://dev.to/vemulakonda559/does-polymorphism-always-require-inheritance-a-python-perspective-3k0n</link>
      <guid>https://dev.to/vemulakonda559/does-polymorphism-always-require-inheritance-a-python-perspective-3k0n</guid>
      <description>&lt;p&gt;Many developers learn polymorphism through inheritance and assume the two concepts are inseparable.&lt;/p&gt;

&lt;p&gt;But does polymorphism actually require inheritance?&lt;/p&gt;

&lt;p&gt;Python provides a surprising answer.&lt;/p&gt;

&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Most OOP tutorials introduce polymorphism through inheritance using a base class, derived classes, and method overriding.&lt;/p&gt;

&lt;p&gt;As a result, many developers naturally form a mental model like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Inheritance
      ↓
Polymorphism
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Over time, this often leads to a common assumption:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Polymorphism requires inheritance.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;But is that really true?&lt;/p&gt;

&lt;p&gt;Python approaches polymorphism differently.&lt;/p&gt;

&lt;p&gt;In many cases, objects can participate in polymorphic behavior without inheriting from a common parent class. What matters is &lt;strong&gt;not where an object comes from, but what it can do.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This leads to an important realization:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Inheritance can enable polymorphism, but it is not always required.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In this article, we'll explore the relationship between inheritance and polymorphism and see how Python's duck typing allows polymorphism to exist even without inheritance.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Common Assumption
&lt;/h2&gt;

&lt;p&gt;If you've studied object-oriented programming, you've probably seen examples like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Animal&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;speak&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;pass&lt;/span&gt;


&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Dog&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Animal&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;speak&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Woof&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Cat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Animal&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;speak&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Meow&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A function can then work with any &lt;code&gt;Animal&lt;/code&gt; object:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;make_sound&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;animal&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;animal&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;speak&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Usage:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nf"&gt;make_sound&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Dog&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;span class="nf"&gt;make_sound&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Cat&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Woof
Meow
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is a classic example of polymorphism. The same function works with different object types, and each object provides its own implementation of &lt;code&gt;speak()&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Because examples like these are so common, many developers naturally form the following mental model:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Inheritance
      ↓
Method Overriding
      ↓
Polymorphism
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Over time, this often becomes:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Polymorphism requires inheritance.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The assumption is understandable because inheritance appears in almost every introductory explanation of polymorphism.&lt;/p&gt;

&lt;p&gt;But inheritance and polymorphism are not the same thing.&lt;/p&gt;

&lt;p&gt;Inheritance is one way to achieve polymorphism, but is it the reason polymorphism works?&lt;/p&gt;

&lt;p&gt;Let's examine the traditional inheritance-based approach more closely.&lt;/p&gt;




&lt;h2&gt;
  
  
  Classic Polymorphism Through Inheritance
&lt;/h2&gt;

&lt;p&gt;Traditionally, polymorphism is demonstrated using inheritance.&lt;/p&gt;

&lt;p&gt;Consider the following example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Animal&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;speak&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nb"&gt;NotImplementedError&lt;/span&gt;


&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Dog&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Animal&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;speak&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Woof&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Cat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Animal&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;speak&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Meow&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A function can work with any object derived from &lt;code&gt;Animal&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;make_sound&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;animal&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;animal&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;speak&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Usage:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nf"&gt;make_sound&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Dog&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;span class="nf"&gt;make_sound&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Cat&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Woof
Meow
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The function doesn't need to know whether it received a &lt;code&gt;Dog&lt;/code&gt; or a &lt;code&gt;Cat&lt;/code&gt;. It simply calls:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;animal&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;speak&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each object provides its own implementation, allowing the same operation to produce different behavior. That's the essence of polymorphism.&lt;/p&gt;

&lt;p&gt;Here, inheritance provides a common interface that makes this possible.&lt;/p&gt;




&lt;h3&gt;
  
  
  Why This Works
&lt;/h3&gt;

&lt;p&gt;Inheritance establishes a common parent class:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Animal
   │
   ├── Dog
   └── Cat
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Both &lt;code&gt;Dog&lt;/code&gt; and &lt;code&gt;Cat&lt;/code&gt; implement:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nf"&gt;speak&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;allowing &lt;code&gt;make_sound()&lt;/code&gt; to work with either object.&lt;/p&gt;

&lt;p&gt;But this raises an important question:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Does &lt;code&gt;make_sound()&lt;/code&gt; really require a common parent class, or does it simply require an object that provides &lt;code&gt;speak()&lt;/code&gt;?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That distinction is important because if polymorphism is fundamentally about behavior, inheritance may not be the real reason the code works.&lt;/p&gt;

&lt;p&gt;To answer that, we first need to understand what polymorphism really is.&lt;/p&gt;




&lt;h2&gt;
  
  
  What Is Polymorphism Really?
&lt;/h2&gt;

&lt;p&gt;At its core, polymorphism is the ability of different objects to respond to the same operation in their own way.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Dog&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;speak&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Woof&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Cat&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;speak&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Meow&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Both classes provide:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nf"&gt;speak&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;but each produces different behavior.&lt;/p&gt;

&lt;p&gt;Now consider this function:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;make_sound&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;animal&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;animal&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;speak&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Usage:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nf"&gt;make_sound&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Dog&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;span class="nf"&gt;make_sound&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Cat&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Woof
Meow
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The same function works with different objects because each provides its own implementation of &lt;code&gt;speak()&lt;/code&gt;. That's polymorphism.&lt;/p&gt;

&lt;p&gt;A useful way to think about it is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Same Operation
       +
Different Implementations
       =
Polymorphism
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notice that this definition says nothing about inheritance.&lt;/p&gt;

&lt;p&gt;The important question is not:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Do these objects inherit from the same parent class?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Instead, ask:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Can these objects respond to the same operation?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If the answer is yes, polymorphism is possible.&lt;/p&gt;




&lt;h3&gt;
  
  
  The Key Idea
&lt;/h3&gt;

&lt;p&gt;Many developers think of polymorphism like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Inheritance
      ↓
Polymorphism
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A more accurate view is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Same Operation
       +
Different Implementations
       =
Polymorphism
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The focus is not on whether objects share a parent class, but on whether they can respond to the same operation.&lt;/p&gt;




&lt;h3&gt;
  
  
  Polymorphism Is About Behavior
&lt;/h3&gt;

&lt;p&gt;Consider a notification system:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;EmailNotifier&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Sending email&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;SMSNotifier&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Sending SMS&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;PushNotifier&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Sending push notification&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A generic function can work with all of them:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;notify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;notifier&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;notifier&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The function only cares that the object provides:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This illustrates an important point: polymorphism depends on behavior, not the specific type of object.&lt;/p&gt;

&lt;p&gt;If behavior is what matters, do we really need inheritance to achieve polymorphism?&lt;/p&gt;

&lt;p&gt;Python's answer is:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Not always.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;And that's where duck typing enters the picture.&lt;/p&gt;




&lt;h2&gt;
  
  
  Polymorphism Through Duck Typing
&lt;/h2&gt;

&lt;p&gt;One of Python's most distinctive features is &lt;strong&gt;duck typing&lt;/strong&gt;, often summarized as:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If it walks like a duck and quacks like a duck, then it can be treated as a duck.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Instead of focusing on an object's inheritance hierarchy, Python focuses on its behavior.&lt;/p&gt;

&lt;p&gt;In other words, the question becomes:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Does this object provide the behavior I need?&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h3&gt;
  
  
  A Polymorphic Example Without Inheritance
&lt;/h3&gt;

&lt;p&gt;Consider the following classes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Dog&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;speak&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Woof&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Cat&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;speak&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Meow&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Cow&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;speak&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Moo&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notice that none of these classes inherit from a common parent.&lt;/p&gt;

&lt;p&gt;A generic function can still work with all of them:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;make_sound&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;animal&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;animal&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;speak&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Usage:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nf"&gt;make_sound&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Dog&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;span class="nf"&gt;make_sound&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Cat&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;span class="nf"&gt;make_sound&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Cow&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Woof
Meow
Moo
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The function works because every object provides &lt;code&gt;speak()&lt;/code&gt;. It depends on behavior, not inheritance.&lt;/p&gt;




&lt;h3&gt;
  
  
  Adding New Types Requires No Changes
&lt;/h3&gt;

&lt;p&gt;Suppose we need to support ducks.&lt;/p&gt;

&lt;p&gt;We can simply add:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Duck&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;speak&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Quack&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Usage:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nf"&gt;make_sound&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Duck&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Quack
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No changes are required to &lt;code&gt;make_sound()&lt;/code&gt;. We simply introduce another object that provides the expected behavior.&lt;/p&gt;




&lt;h3&gt;
  
  
  The Real Source of Polymorphism
&lt;/h3&gt;

&lt;p&gt;Notice that &lt;code&gt;make_sound()&lt;/code&gt; never checks whether an object inherits from &lt;code&gt;Animal&lt;/code&gt;, for example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nf"&gt;isinstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;animal&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Animal&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Its only requirement is that the object supports:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;animal&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;speak&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This reveals an important insight:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The true source of polymorphism is shared behavior, not shared ancestry.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Inheritance can provide that behavior, but so can duck typing.&lt;/p&gt;




&lt;p&gt;At this point, we can answer the original question:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Does polymorphism always require inheritance?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In Python, the answer is:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;No.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Different objects can participate in polymorphic behavior as long as they support the same operation, even without an inheritance relationship.&lt;/p&gt;




&lt;h2&gt;
  
  
  When Inheritance Is Still Useful
&lt;/h2&gt;

&lt;p&gt;At this point, it might be tempting to conclude:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If polymorphism can exist without inheritance, then inheritance is unnecessary.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That would be the wrong conclusion.&lt;/p&gt;

&lt;p&gt;The lesson is not:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Avoid inheritance
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The lesson is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Use inheritance when it solves a problem
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Shared Behavior
&lt;/h3&gt;

&lt;p&gt;Consider the following example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Animal&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;eat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Eating&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Sleeping&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Dog&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Animal&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;speak&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Woof&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Cat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Animal&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;speak&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Meow&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, &lt;code&gt;Dog&lt;/code&gt; and &lt;code&gt;Cat&lt;/code&gt; inherit common behavior from &lt;code&gt;Animal&lt;/code&gt; instead of duplicating the same code, improving maintainability and reducing repetition.&lt;/p&gt;




&lt;h3&gt;
  
  
  "Is-A" Relationships
&lt;/h3&gt;

&lt;p&gt;Inheritance is often appropriate when one type is a specialized form of another:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Dog is an Animal

Manager is an Employee

SavingsAccount is an Account
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In such cases, inheritance naturally models the domain.&lt;/p&gt;




&lt;h3&gt;
  
  
  Inheritance and Polymorphism Can Work Together
&lt;/h3&gt;

&lt;p&gt;Inheritance and polymorphism often complement each other:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;PaymentMethod&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;process&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nb"&gt;NotImplementedError&lt;/span&gt;


&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;CreditCard&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;PaymentMethod&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;process&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Processing &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; using credit card&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;UPI&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;PaymentMethod&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;process&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Processing &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; using UPI&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A generic function can work with any payment method:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;make_payment&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;method&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;method&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;process&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is a perfectly valid example of inheritance-based polymorphism.&lt;/p&gt;




&lt;h3&gt;
  
  
  The Real Lesson
&lt;/h3&gt;

&lt;p&gt;Inheritance and polymorphism are related, but they solve different problems:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Inheritance
      ↓
Code Reuse and Relationships

Polymorphism
      ↓
Behavioral Flexibility
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Inheritance can enable polymorphism, but it is not a prerequisite for it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Understanding this distinction helps us choose the right tool for the problem at hand.
&lt;/h2&gt;

&lt;h2&gt;
  
  
  Key Takeaways
&lt;/h2&gt;

&lt;p&gt;Let's return to the original question:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Does polymorphism always require inheritance?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The answer is:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;No. Polymorphism does not require inheritance.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Throughout this article, we've seen that:&lt;/p&gt;

&lt;p&gt;✅ &lt;strong&gt;Inheritance and polymorphism are different concepts.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Inheritance models relationships and promotes code reuse, while polymorphism enables different objects to respond to the same operation.&lt;/p&gt;




&lt;p&gt;✅ &lt;strong&gt;Inheritance can enable polymorphism.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Traditional OOP often achieves polymorphism through inheritance and method overriding.&lt;/p&gt;




&lt;p&gt;✅ &lt;strong&gt;Duck typing also enables polymorphism.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In Python, objects don't need a common parent class—they simply need to provide the expected behavior.&lt;/p&gt;




&lt;p&gt;✅ &lt;strong&gt;Behavior is the key.&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Same Operation
       +
Different Implementations
       =
Polymorphism
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Focus on what objects can do, not necessarily what they inherit from.&lt;/p&gt;




&lt;p&gt;✅ &lt;strong&gt;Inheritance is still valuable.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Use inheritance to model relationships, share behavior, and reduce duplication.&lt;/p&gt;




&lt;h3&gt;
  
  
  The Most Important Insight
&lt;/h3&gt;

&lt;p&gt;Many developers start with this mental model:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Inheritance
      ↓
Polymorphism
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A more accurate view is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Inheritance
      ↓
One Way to Enable Polymorphism
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's perhaps the most important lesson Python teaches about polymorphism.&lt;/p&gt;




&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Polymorphism is often taught through inheritance, making it easy to assume the two concepts are inseparable.&lt;/p&gt;

&lt;p&gt;As we've seen, inheritance is one way to enable polymorphism—but it is not the only way.&lt;/p&gt;

&lt;p&gt;Python demonstrates this particularly well through duck typing, where objects can participate in polymorphic behavior simply by providing the expected methods.&lt;/p&gt;

&lt;p&gt;This leads to an important realization:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Polymorphism is fundamentally about behavior, not inheritance.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Inheritance remains a valuable tool for code reuse and modeling relationships between classes. It should be used because it solves those problems—not because polymorphism depends on it.&lt;/p&gt;

&lt;p&gt;The next time you design a system, ask yourself:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Do these objects need a common parent class, or do they simply need to provide the same behavior?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Perhaps that's the most Pythonic lesson of all:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;What an object can do is often more important than what it inherits from.&lt;/p&gt;
&lt;/blockquote&gt;




</description>
      <category>python</category>
      <category>oop</category>
      <category>softwareengineering</category>
      <category>programming</category>
    </item>
    <item>
      <title>Stop Editing Working Code: Understanding the Open/Closed Principle in Python</title>
      <dc:creator>Rajesh Vemulakonda</dc:creator>
      <pubDate>Fri, 17 Jul 2026 05:52:11 +0000</pubDate>
      <link>https://dev.to/vemulakonda559/stop-editing-working-code-understanding-the-openclosed-principle-in-python-502b</link>
      <guid>https://dev.to/vemulakonda559/stop-editing-working-code-understanding-the-openclosed-principle-in-python-502b</guid>
      <description>&lt;p&gt;Every time a new requirement arrives, do you find yourself opening the same function and adding another &lt;code&gt;elif&lt;/code&gt; block?&lt;/p&gt;

&lt;p&gt;If yes, your code may be signaling a design problem.&lt;/p&gt;

&lt;p&gt;Most software bugs aren't caused by adding new features.&lt;/p&gt;

&lt;p&gt;They're caused by modifying existing features that were already working.&lt;/p&gt;

&lt;p&gt;The Open/Closed Principle (OCP) is one of the most effective ways to reduce that risk.&lt;/p&gt;

&lt;p&gt;Consider a simple export utility:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;export&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;file_type&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;file_type&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;pdf&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="nf"&gt;export_pdf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;file_type&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;csv&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="nf"&gt;export_csv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A few weeks later:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;file_type&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;json&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nf"&gt;export_json&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;file_type&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;xml&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nf"&gt;export_xml&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;file_type&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;html&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nf"&gt;export_html&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The code still works.&lt;/p&gt;

&lt;p&gt;The problem is that every new requirement forces us to modify existing, tested code.&lt;/p&gt;

&lt;p&gt;As the application grows, this pattern increases:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Maintenance effort&lt;/li&gt;
&lt;li&gt;Regression testing&lt;/li&gt;
&lt;li&gt;Risk of introducing bugs&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is exactly the problem the &lt;strong&gt;Open/Closed Principle (OCP)&lt;/strong&gt; tries to solve.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Software entities should be open for extension but closed for modification.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In simple terms:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Add new behavior without repeatedly editing code that already works.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Most discussions stop at inheritance and polymorphism. Python, however, provides several additional ways to achieve OCP that often feel more natural.&lt;/p&gt;

&lt;p&gt;Let's explore them.&lt;/p&gt;




&lt;h2&gt;
  
  
  OCP Through Duck Typing
&lt;/h2&gt;

&lt;p&gt;Many OOP examples start by creating a base class:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Exporter&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;export&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;pass&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and then inheriting from it.&lt;/p&gt;

&lt;p&gt;Python often doesn't need that.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;PDFExporter&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;export&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Exporting PDF&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;CSVExporter&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;export&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Exporting CSV&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;JSONExporter&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;export&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Exporting JSON&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A generic function can simply rely on behavior:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;export_data&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;exporter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;exporter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;export&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Usage:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nf"&gt;export_data&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;PDFExporter&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;export_data&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;CSVExporter&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;export_data&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;JSONExporter&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The function doesn't care about inheritance.&lt;/p&gt;

&lt;p&gt;It only cares that the object provides an &lt;code&gt;export()&lt;/code&gt; method.&lt;/p&gt;

&lt;p&gt;Need XML support?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;XMLExporter&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;export&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Exporting XML&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No existing code changes.&lt;/p&gt;

&lt;p&gt;That's extension without modification.&lt;/p&gt;




&lt;h2&gt;
  
  
  OCP Through First-Class Functions
&lt;/h2&gt;

&lt;p&gt;Python treats functions as first-class objects.&lt;/p&gt;

&lt;p&gt;That means behavior itself can become an extension point.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;export_pdf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Exporting PDF&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;export_csv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Exporting CSV&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;export_json&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Exporting JSON&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Generic exporter:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;export_data&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;exporter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="nf"&gt;exporter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Usage:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nf"&gt;export_data&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;export_pdf&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;export_data&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;export_csv&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;export_data&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;export_json&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Adding support for XML becomes trivial:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;export_xml&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Exporting XML&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nf"&gt;export_data&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;export_xml&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Again, existing code remains untouched.&lt;/p&gt;




&lt;h2&gt;
  
  
  OCP Through Registration Decorators
&lt;/h2&gt;

&lt;p&gt;As systems grow, we often need a way to discover available functionality automatically.&lt;/p&gt;

&lt;p&gt;Decorators can act as registration mechanisms.&lt;/p&gt;

&lt;p&gt;Start with a registry:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;exporters&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Create a registration decorator:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;register&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;file_type&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;decorator&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;func&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;exporters&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;file_type&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;func&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;func&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;decorator&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Register exporters:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nd"&gt;@register&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;pdf&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;export_pdf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Exporting PDF&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nd"&gt;@register&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;csv&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;export_csv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Exporting CSV&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Dispatcher:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;export&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;file_type&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;exporters&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;file_type&lt;/span&gt;&lt;span class="p"&gt;](&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Adding a new format becomes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nd"&gt;@register&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;xml&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;export_xml&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Exporting XML&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No dispatcher changes required.&lt;/p&gt;

&lt;p&gt;This is the foundation of many plugin-style architectures.&lt;/p&gt;




&lt;h2&gt;
  
  
  OCP Through &lt;code&gt;functools.singledispatch&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;Python's standard library includes an elegant extension mechanism called &lt;code&gt;singledispatch&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Without it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;export&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nf"&gt;isinstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="bp"&gt;...&lt;/span&gt;

    &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="nf"&gt;isinstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="bp"&gt;...&lt;/span&gt;

    &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="nf"&gt;isinstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="bp"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With &lt;code&gt;singledispatch&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;functools&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;singledispatch&lt;/span&gt;


&lt;span class="nd"&gt;@singledispatch&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;export&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;TypeError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Unsupported type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Register implementations:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nd"&gt;@export.register&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;_&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Exporting list&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nd"&gt;@export.register&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;_&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Exporting dictionary&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nd"&gt;@export.register&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;_&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Exporting string&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Need tuple support?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nd"&gt;@export.register&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;_&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;tuple&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Exporting tuple&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No changes to the original function.&lt;/p&gt;

&lt;p&gt;Just register another implementation.&lt;/p&gt;




&lt;h2&gt;
  
  
  When OCP Becomes Overengineering
&lt;/h2&gt;

&lt;p&gt;Not every problem needs abstractions.&lt;/p&gt;

&lt;p&gt;This code is perfectly fine:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;age&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;18&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Eligible&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Not Eligible&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Creating:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;EligibilityStrategy&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="bp"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;would likely make the code worse, not better.&lt;/p&gt;

&lt;p&gt;The goal is not to eliminate every conditional statement.&lt;/p&gt;

&lt;p&gt;The goal is to identify areas that genuinely evolve over time.&lt;/p&gt;

&lt;p&gt;Examples include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;File exporters&lt;/li&gt;
&lt;li&gt;Payment processors&lt;/li&gt;
&lt;li&gt;Notification systems&lt;/li&gt;
&lt;li&gt;Authentication providers&lt;/li&gt;
&lt;li&gt;Data parsers&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These are natural candidates for extension.&lt;/p&gt;




&lt;h2&gt;
  
  
  Want the Full Version?
&lt;/h2&gt;

&lt;p&gt;This article focuses on Python-specific techniques for applying the Open/Closed Principle.&lt;/p&gt;

&lt;p&gt;For a deeper dive covering:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Inheritance&lt;/li&gt;
&lt;li&gt;Polymorphism&lt;/li&gt;
&lt;li&gt;Strategy Pattern&lt;/li&gt;
&lt;li&gt;Practical design trade-offs&lt;/li&gt;
&lt;li&gt;A decision checklist&lt;/li&gt;
&lt;li&gt;Detailed examples&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;see the full companion guide on GitHub:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/Vemulakonda559/open-closed-principle-python" rel="noopener noreferrer"&gt;https://github.com/Vemulakonda559/open-closed-principle-python&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Key Takeaway
&lt;/h2&gt;

&lt;p&gt;Many developers associate the Open/Closed Principle with inheritance.&lt;/p&gt;

&lt;p&gt;Python offers a broader perspective.&lt;/p&gt;

&lt;p&gt;We can achieve OCP through:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Duck Typing&lt;/li&gt;
&lt;li&gt;First-Class Functions&lt;/li&gt;
&lt;li&gt;Registration Decorators&lt;/li&gt;
&lt;li&gt;&lt;code&gt;functools.singledispatch&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The common theme is always the same:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Add new behavior without repeatedly modifying existing behavior.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The next time you find yourself adding another branch to a growing &lt;code&gt;if-elif&lt;/code&gt; chain, pause and ask:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Can this be extended instead?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That question is often the first step toward writing code that is easier to maintain, test, and evolve.&lt;/p&gt;

</description>
      <category>python</category>
      <category>solidprinciples</category>
      <category>oop</category>
      <category>designpatterns</category>
    </item>
    <item>
      <title>Why Does obj.method() Automatically Receive self? A Deep Dive into Python Method Binding</title>
      <dc:creator>Rajesh Vemulakonda</dc:creator>
      <pubDate>Wed, 15 Jul 2026 04:13:27 +0000</pubDate>
      <link>https://dev.to/vemulakonda559/why-does-objmethod-automatically-receive-self-a-deep-dive-into-python-method-binding-344o</link>
      <guid>https://dev.to/vemulakonda559/why-does-objmethod-automatically-receive-self-a-deep-dive-into-python-method-binding-344o</guid>
      <description>&lt;p&gt;Every Python programmer writes:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;obj.method()&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;But have you ever wondered why Python automatically passes &lt;code&gt;self&lt;/code&gt;?&lt;/p&gt;

&lt;p&gt;While studying Python internals, I explored how method binding works, how descriptors participate in attribute access, and how Python creates bound method objects behind the scenes.&lt;/p&gt;

&lt;p&gt;This article documents that learning journey.&lt;/p&gt;

&lt;h2&gt;
  
  
  A Simple Example
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Demo&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;hello&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Hello&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;obj&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Demo&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;hello&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We didn't pass &lt;code&gt;self&lt;/code&gt;.&lt;br&gt;
So where did it come from?&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Demo.hello(obj)&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;This produces the same result.&lt;/p&gt;

&lt;p&gt;This is the first clue that Python is doing something special behind the scenes.&lt;/p&gt;

&lt;p&gt;If &lt;code&gt;obj.hello()&lt;/code&gt; and &lt;code&gt;Demo.hello(obj)&lt;/code&gt; behave the same way, then Python must somehow be attaching &lt;code&gt;obj&lt;/code&gt; automatically when we access the method through an instance.&lt;/p&gt;

&lt;p&gt;When Python evaluates:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;obj.hello&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;it does not immediately execute the function.&lt;/p&gt;

&lt;p&gt;Instead, Python performs attribute lookup and invokes the descriptor protocol.&lt;/p&gt;

&lt;p&gt;The function object is transformed into a bound method object that already contains a reference to &lt;code&gt;obj&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;When the method is later called, &lt;code&gt;obj&lt;/code&gt; is automatically supplied as the first argument (&lt;code&gt;self&lt;/code&gt;).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;obj.hello
     ↓
function.\_\_get\_\_(obj, Demo)
     ↓
Bound Method Created
     ↓
self Attached
     ↓
Method Executes
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Complete Notes
&lt;/h2&gt;

&lt;p&gt;This article provides a brief overview.&lt;/p&gt;

&lt;p&gt;The complete experiments, explanations, and code examples are available in the GitHub repository:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/Vemulakonda559/python-method-binding" rel="noopener noreferrer"&gt;https://github.com/Vemulakonda559/python-method-binding&lt;/a&gt;&lt;/p&gt;

</description>
      <category>python</category>
      <category>programming</category>
      <category>softwareengineering</category>
      <category>oop</category>
    </item>
  </channel>
</rss>
