<head> <title>Evan Pratten</title> <meta charset="utf-8" /> <meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no" /> <!-- Begin Jekyll SEO tag v2.6.1 --> <title>Doing Python OOP the wrong way | Evan Pratten</title> <meta name="generator" content="Jekyll v3.8.6" /> <meta property="og:title" content="Doing Python OOP the wrong way" /> <meta property="og:locale" content="en_US" /> <meta name="description" content="In the name of science!" /> <meta property="og:description" content="In the name of science!" /> <link rel="canonical" href="http://0.0.0.0:4000/blog/2019/09/07/wrong-python" /> <meta property="og:url" content="http://0.0.0.0:4000/blog/2019/09/07/wrong-python" /> <meta property="og:site_name" content="Evan Pratten" /> <meta property="og:type" content="article" /> <meta property="article:published_time" content="2019-09-07T09:13:00-04:00" /> <script type="application/ld+json"> {"datePublished":"2019-09-07T09:13:00-04:00","dateModified":"2019-09-07T09:13:00-04:00","@type":"BlogPosting","mainEntityOfPage":{"@type":"WebPage","@id":"http://0.0.0.0:4000/blog/2019/09/07/wrong-python"},"url":"http://0.0.0.0:4000/blog/2019/09/07/wrong-python","description":"In the name of science!","headline":"Doing Python OOP the wrong way","@context":"https://schema.org"}</script> <!-- End Jekyll SEO tag --> <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous"> <link rel="stylesheet" href="/assets/css/main.css"> <link rel="stylesheet" href="/assets/css/github-syntax.css"> <link href="https://fonts.googleapis.com/css?family=IBM+Plex+Mono:400,400i|IBM+Plex+Sans:100,100i,400,400i,700,700i" rel="stylesheet"> <link href="https://stackpath.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet" integrity="sha384-wvfXpqpZZVQGK6TAh5PVlGOfQNHSoD2xbE+QkPxCAFlNEevoEH3Sl0sibVcOQVnN" crossorigin="anonymous"> </head> <body> <div class="site-ctr"> <!-- Navbar --> <nav class="navbar navbar-dark sticky-top bg-dark navbar-expand-lg"> <!-- Navbar content --> <!-- <div class="container"> --> <a class="navbar-brand" href="/">Evan Pratten</a> <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarNavAltMarkup" aria-controls="navbarNavAltMarkup" aria-expanded="false" aria-label="Toggle navigation"> <span class="navbar-toggler-icon"></span> </button> <div class="collapse navbar-collapse" id="navbarNavAltMarkup"> <div class="navbar-nav ml-auto"> <a class="nav-item nav-link" href="/blog">Blog</a> <a class="nav-item nav-link" href="/projects">Projects</a> <!-- <a class="nav-item nav-link" href="/documentation">Documentation</a> --> <a class="nav-item nav-link" href="/about">About</a> </div> <!-- </div> --> </div> </nav> <!-- <div style="height:5vh"></div> --> <!-- Header --> <!-- <div class="header"> <div class="container"> <div class="content"> </div> </div> <div class="header-gap"></div> </div> --> <div class="reactive-bg"> <div class="post container"> <h1>Doing Python OOP the wrong way </h1> <h4>In the name of science! </h4> <hr> <p><em>2019-09-07 09:13:00 -0400 </em></p> <br> <p>If you know me, you probably know of the many weird things I do with python. Most recent of which being this <a href="https://en.wikipedia.org/wiki/Fizz_buzz">FizzBuzz</a> implementation in one line of python code:</p> <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">_</span><span class="o">=</span><span class="p">[</span><span class="k">print</span><span class="p">(</span><span class="s">"FizzBuzz"</span><span class="p">[</span><span class="n">_</span><span class="o">*</span><span class="n">_</span><span class="o">%</span><span class="mi">3</span><span class="o">*</span><span class="mi">4</span><span class="p">:</span><span class="mi">8</span><span class="o">--</span><span class="n">_</span><span class="o">**</span><span class="mi">4</span><span class="o">%</span><span class="mi">5</span><span class="p">]</span> <span class="ow">or</span> <span class="n">_</span><span class="p">)</span> <span class="k">for</span> <span class="n">_</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">101</span><span class="p">)]</span> </code></pre></div></div> <p>This installment of “weird things I do with python” will not focus on one-liners (that’s going on my todo list though). But instead, playing with Python’s classes and object system.</p> <h2 id="a-quick-introduction-to-classes">A quick introduction to classes</h2> <p>Im going to assume that you, the reader, have some reasonable knowledge of how computers work, and OOP concepts. If you do not, there are <a href="https://medium.com/swlh/5-free-object-oriented-programming-online-courses-for-programmers-156afd0a3a73">many great online resources</a> to help you out.</p> <p>As a quick refresher, this is the Python syntax for a basic class:</p> <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">class</span> <span class="nc">MyClass</span><span class="p">:</span> <span class="c1"># This is the constructor. __init__ is an overridable python built-in </span> <span class="k">def</span> <span class="nf">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">arg1</span><span class="p">:</span> <span class="nb">int</span><span class="p">):</span> <span class="c1"># Here we set the class' scoped my_number to arg1 </span> <span class="bp">self</span><span class="o">.</span><span class="n">my_number</span> <span class="o">=</span> <span class="n">arg1</span> <span class="k">def</span> <span class="nf">printMyNumber</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span> <span class="k">print</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">my_number</span><span class="p">)</span> </code></pre></div></div> <p>This is really just a fancy setter and getter. Here is some example usage:</p> <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">my_object</span> <span class="o">=</span> <span class="n">MyClass</span><span class="p">(</span><span class="mi">10</span><span class="p">)</span> <span class="n">my_object</span><span class="o">.</span><span class="n">printMyNumber</span><span class="p">()</span> <span class="c1"># Prints 10 </span></code></pre></div></div> <h2 id="noticing-something-odd">Noticing something odd</h2> <p>Before reading the following, keep in mind that (as of now) I have not actually looked at the Python interpreter’s source code enough to know about their memory system. The following is just an educated guess.</p> <p>Looking at any python class, you may notice that <strong>at least</strong> 1 argument is required. <code class="highlighter-rouge">self</code> is used to access the class’ data from itself. This is not present in most other languages I know, which means there might be something interesting happening behind the scenes. Here is a re-implementation of <code class="highlighter-rouge">MyClass</code> from above in java:</p> <div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">public</span> <span class="kd">class</span> <span class="nc">MyClass</span> <span class="o">{</span> <span class="kt">int</span> <span class="n">my_int</span><span class="o">;</span> <span class="kd">public</span> <span class="nf">MyClass</span><span class="o">(</span><span class="kt">int</span> <span class="n">arg1</span><span class="o">){</span> <span class="n">my_int</span> <span class="o">=</span> <span class="n">arg1</span><span class="o">;</span> <span class="o">}</span> <span class="kd">public</span> <span class="kt">void</span> <span class="nf">printMyNumber</span><span class="o">(){</span> <span class="nc">System</span><span class="o">.</span><span class="na">out</span><span class="o">.</span><span class="na">println</span><span class="o">(</span><span class="n">my_int</span><span class="o">);</span> <span class="o">}</span> <span class="o">}</span> </code></pre></div></div> <p>Notice the fact that there is no <code class="highlighter-rouge">self</code>? Yet Java methods can still access class data.</p> <h2 id="implementing-objects-in-a-non-object-oriented-language">Implementing objects in a non-object oriented language</h2> <p>In a non-OOP language (like C), objects can be faked by creating <a href="https://en.wikipedia.org/wiki/Struct_(C_programming_language)">structures</a> and some standard functions. These functions then take a pointer to their “parent” structure. Confusing? yes. But it works, and I see it used all over the place. Here a pseudocode example:</p> <div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>struct MyClass { int my_int; // Scpoed int } fn printMyNumber(MyClass* self){ print(self.my_int); } </code></pre></div></div> <p><code class="highlighter-rouge">printMyNumber</code> takes a pointer to it’s “parent class”, called <code class="highlighter-rouge">self</code>. Look familiar? This is how Python works.</p> <h2 id="lets-do-some-python">Let’s do some Python</h2> <p>Alright.. Time for some “broken” Python. Here is yet another implementation of <code class="highlighter-rouge">MyClass</code>, except this time, each function is globally scoped:</p> <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="c1"># Private, globally scoped functions </span><span class="k">def</span> <span class="nf">_init_myclass</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">arg1</span><span class="p">:</span> <span class="nb">int</span><span class="p">):</span> <span class="bp">self</span><span class="o">.</span><span class="n">my_number</span> <span class="o">=</span> <span class="n">arg1</span> <span class="k">def</span> <span class="nf">_myclass_printMyNumber</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span> <span class="k">print</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">my_number</span><span class="p">)</span> <span class="c1"># struct-like class containing function pointers </span><span class="k">class</span> <span class="nc">MyClass</span><span class="p">:</span> <span class="n">__init__</span> <span class="o">=</span> <span class="n">_init_myclass</span> <span class="n">printMyNumber</span> <span class="o">=</span> <span class="n">_myclass_printMyNumber</span> </code></pre></div></div> <p>This code will still function like a normal class. Unlike a regular class definition, the above code defines the constructor and <code class="highlighter-rouge">printMyNumber</code> methods in the global scope (marked as private with an underscore). A class is then created with function pointers to each of the global functions. This means that calling <code class="highlighter-rouge">MyClass.printMyNumber</code> will point to, and execute <code class="highlighter-rouge">_myclass_printMyNumber</code>. The interpreter still treats the underscore functions as members of <code class="highlighter-rouge">MyClass</code>, and passes the <code class="highlighter-rouge">self</code> argument along to them.</p> <h2 id="why">Why?</h2> <p>I have absolutely no idea why this would ever be useful. If you think you should start doing this in your code, <strong>don’t</strong>. It leads to very messy and confusing code, and is bad practice in just about every way.</p> <p>The point of this post is to show yet another instance of the Python interpreter saying “<a href="https://www.urbandictionary.com/define.php?term=idgaf">idgaf</a>”, and letting us have a little fun.</p> </div> </div> </div> <!-- <div id="particles-js"></div> --> <div class="container foot" style="text-align:center;"> <br> <span class="site-info"> Site design by: <a href="https://retrylife.ca">Evan Pratten</a> | This site was last updated at: 2019-11-20 10:04:40 -0500 </span> </div> <!-- Brython --> <script src="/assets/js/brython.js"></script> <script src="/assets/js/brython_stdlib.js"></script> <script> function startPY(){ brython(); console.log("Started Python") } window.onload = startPY; </script> <script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js" integrity="sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1" crossorigin="anonymous"></script> <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js" integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM" crossorigin="anonymous"></script> <!-- Offsets for links --> <script> (function ($, window) { var adjustAnchor = function () { var $anchor = $(':target'), fixedElementHeight = 100; if ($anchor.length > 0) { window.scrollTo(0, $anchor.offset().top - fixedElementHeight); } }; $(window).on('hashchange load', function () { adjustAnchor(); }); })(jQuery, window); </script> <!-- Global site tag (gtag.js) - Google Analytics --> <script async src="https://www.googletagmanager.com/gtag/js?id=UA-74118570-2"></script> <script> window.dataLayer = window.dataLayer || []; function gtag() { dataLayer.push(arguments); } gtag('js', new Date()); gtag('config', 'UA-74118570-2'); </script> <!-- particles --> <script> var body = document.body var particles = document.getElementById("particles-js") particles.style.height = body.scrollHeight + "px" console.log(body.scrollHeight) </script> <script src="/assets/js/particles.min.js"></script> <script> particlesJS.load('particles-js', '/assets/js/particles.json', function () { console.log('callback - particles.js config loaded'); }); </script> <!-- Twitter embeds --> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script> </body>