<?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>Forem: Tamir Bahar</title>
    <description>The latest articles on Forem by Tamir Bahar (@tmr232).</description>
    <link>https://forem.com/tmr232</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.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F372%2F1386239.jpeg</url>
      <title>Forem: Tamir Bahar</title>
      <link>https://forem.com/tmr232</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/tmr232"/>
    <language>en</language>
    <item>
      <title>More Memory Profiling (in Python)</title>
      <dc:creator>Tamir Bahar</dc:creator>
      <pubDate>Fri, 02 Jul 2021 15:10:54 +0000</pubDate>
      <link>https://forem.com/tmr232/more-memory-profiling-in-python-43k0</link>
      <guid>https://forem.com/tmr232/more-memory-profiling-in-python-43k0</guid>
      <description>&lt;h2&gt;
  
  
  TL;DR
&lt;/h2&gt;

&lt;p&gt;Graph memory-usage over time, correlate with logs, profit.&lt;/p&gt;

&lt;h2&gt;
  
  
  Overconfidence
&lt;/h2&gt;

&lt;p&gt;Recently, I had to reduce the memory consumption of a Python process that became entirely unreasonable. Now, a while back I wrote about &lt;a href="https://dev.to/tmr232/finding-a-memory-leak-in-my-python-code-j73"&gt;finding memory leaks in Python&lt;/a&gt;. I was pleased with myself and sure that with the knowledge I gained then, I can surely get this done!&lt;/p&gt;

&lt;p&gt;And oh, was I wrong...&lt;/p&gt;

&lt;h2&gt;
  
  
  Harsh Reality
&lt;/h2&gt;

&lt;p&gt;You see, both &lt;a href="https://pympler.readthedocs.io/en/latest/"&gt;pympler&lt;/a&gt; and &lt;a href="https://docs.python.org/3/library/tracemalloc.html"&gt;tracemalloc&lt;/a&gt; are wonderful tools. But like all tools, they have limitations. When you have a long-running (days) process with many (hundreds of millions) objects, the memory and performance costs of your tools add up quite significantly. Waiting for &lt;code&gt;pympler&lt;/code&gt; to query &lt;em&gt;all objects&lt;/em&gt; takes forever, and following references is completely impractical; viewing &lt;code&gt;tracemalloc&lt;/code&gt; statistics is nice, but doesn't help you narrow things down enough.&lt;/p&gt;

&lt;p&gt;So, after 2 weeks of zero-to-minimal improvements (though I was &lt;em&gt;sure&lt;/em&gt; I'm on the right track) I decided to try a different approach to understanding the memory usage of my code.&lt;/p&gt;

&lt;h2&gt;
  
  
  To The Rescue
&lt;/h2&gt;

&lt;p&gt;Enter &lt;a href="https://gist.github.com/tmr232/4a10e17ddf4aefcc0c94a15bdddc58f4"&gt;memlog.py&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;memlog&lt;/code&gt; is a simple, naive tool. It tracks the overall memory usage on a machine, and logs it (with a timestamp) to a CSV. That's it. While the recorded data may include significant noise, running your code (&amp;amp; &lt;code&gt;memlog&lt;/code&gt;) inside a container can reduce it significantly. Also, background memory noise tends to be insignificant when your process hogging all of your memory...&lt;/p&gt;

&lt;p&gt;So, I ran my process (with logs), ran &lt;code&gt;memlog&lt;/code&gt;, and plotted a memory-over-time graph:&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--yJjRf5do--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/g7m4m6kyo0qmbr36x6jv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--yJjRf5do--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/g7m4m6kyo0qmbr36x6jv.png" alt="The image shows a graph of memory-usage over time. The graph shows a near-instant 4.5-unit rise at the start, then a slow 2-unit rise over a long time, then a near-instant decline back to 0 at the end." width="800" height="532"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And oh, oh no.&lt;/p&gt;

&lt;h2&gt;
  
  
  Insight
&lt;/h2&gt;

&lt;p&gt;Looking at the graph, we can divide it into 3 parts:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;A near-instant rise at the beginning. This is by far the bulk of the memory-usage increase;&lt;/li&gt;
&lt;li&gt;A slow, gradual increase over the entire time-scale;&lt;/li&gt;
&lt;li&gt;A near-instant drop in memory-usage.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Those parts are basically:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Loading the data-set and various initialization;&lt;/li&gt;
&lt;li&gt;The bulk of the processing;&lt;/li&gt;
&lt;li&gt;Program termination.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;And for the past 2 weeks I've been busy reducing the memory-usage of... the second part. Being absolutely sure it's the most significant.&lt;/p&gt;

&lt;p&gt;So yeah, that hurt. But only for a short time. For you see, with this newfound knowledge I could safely focus on the first few minutes of execution and disregard the rest for the time being.&lt;/p&gt;

&lt;p&gt;True. I'll have to test the whole thing once I'm make any significant changes. Memory-usage might spike at a later point. Memory-optimization may cause performance degradation. But unless I reduce that uptick at the beginning I won't get any significant improvements.&lt;/p&gt;

&lt;h2&gt;
  
  
  Profit
&lt;/h2&gt;

&lt;p&gt;A week later, we managed to reduce memory-usage by 30% while &lt;em&gt;reducing&lt;/em&gt; overall processing time by a similar percentage. We had to:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Add a de-duplicating weakref based cache;&lt;/li&gt;
&lt;li&gt;Add a pre-processing step;&lt;/li&gt;
&lt;li&gt;Make our code more cache-friendly by sorting our data;&lt;/li&gt;
&lt;li&gt;Remove a massively over-engineered control mechanism.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;But it was all made possible by &lt;em&gt;focusing on the right part&lt;/em&gt;. Had I not plotted that memory graph, I could've easily spent another 2 weeks without any significant progress.&lt;/p&gt;

&lt;h1&gt;
  
  
  Old &amp;amp; Wise
&lt;/h1&gt;

&lt;p&gt;So whatever you do, I highly suggest you graph your data. No need to be smart about it. Log it, graph it, correlate to your logs.&lt;/p&gt;

</description>
      <category>python</category>
      <category>optimization</category>
    </item>
    <item>
      <title>GitLab CI Tricks</title>
      <dc:creator>Tamir Bahar</dc:creator>
      <pubDate>Wed, 10 Mar 2021 09:02:10 +0000</pubDate>
      <link>https://forem.com/tmr232/gitlab-ci-tricks-12cc</link>
      <guid>https://forem.com/tmr232/gitlab-ci-tricks-12cc</guid>
      <description>&lt;p&gt;In writing our CI setup at Vdoo, we came across some interesting challenges. Having solved them and used the solutions for quite a while, we decided it is best to share, and hopefully save others some time and effort solving similar problems.&lt;/p&gt;

&lt;p&gt;Of course, there are alternative solutions to the challenges we have dealt with, and some solutions are probably superior to ours. We are happy to hear about such solutions and to improve our own.&lt;/p&gt;

&lt;p&gt;As for the code presented in this post - it was extracted from our CI and cleaned up a bit. As such, it is missing some necessary boilerplate. It will not work as-is, and some work will be required to adapt it to your CI. That said, it should clearly lay out the solutions. (You can think of it as slide-ware.)&lt;/p&gt;

&lt;h2&gt;
  
  
  LFS-Check
&lt;/h2&gt;

&lt;p&gt;All transitions can be bumpy. For us, the transition from storing binary files as regular git blobs to storing them using LFS was one such bumpy transition.&lt;/p&gt;

&lt;p&gt;We made sure to include all the LFS-relevant files &amp;amp; patterns in a .gitattributes file, but ensuring everyone (including people who only occasionally work on the relevant repo) properly setup their environments for LFS took some time. In the mean-time, we kept getting files that should be in LFS committed and pushed as regular files in Merge-Requests.&lt;/p&gt;

&lt;p&gt;To circumvent that, we set up a simple check at the start of our CI process to ensure all relevant files are indeed stored in LFS.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;lfs-check&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;only&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;refs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;merge_requests&lt;/span&gt;
  &lt;span class="na"&gt;script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;git lfs install&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;git add --renormalize -u&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
      &lt;span class="s"&gt;if ! git diff --cached --name-only --exit-code ; then&lt;/span&gt;
        &lt;span class="s"&gt;echo&lt;/span&gt;
        &lt;span class="s"&gt;echo&lt;/span&gt;
        &lt;span class="s"&gt;echo "=============================="&lt;/span&gt;
        &lt;span class="s"&gt;echo "#  Please renormalize files  #"&lt;/span&gt;
        &lt;span class="s"&gt;echo "=============================="&lt;/span&gt;
        &lt;span class="s"&gt;echo&lt;/span&gt;
        &lt;span class="s"&gt;echo "git add -u --renormalize"&lt;/span&gt;
        &lt;span class="s"&gt;echo "git commit --amend"&lt;/span&gt;
        &lt;span class="s"&gt;exit 1&lt;/span&gt;
      &lt;span class="s"&gt;fi&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When people pushed the files the wrong way - the CI would fail with an informative error and instructions.&lt;/p&gt;

&lt;h2&gt;
  
  
  Required Commit
&lt;/h2&gt;

&lt;p&gt;Every so often a change is made to the code, rendering the code before the change unworkable or irrelevant. This can happen for many reasons. Here are some examples:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;A bug was fixed in the CI. This is all too common when forgetting to properly lock your dependencies (including recursive ones!)&lt;/li&gt;
&lt;li&gt;A very time-consuming update was made (re-training an ML model, anyone?)&lt;/li&gt;
&lt;li&gt;The change is significant and will make rebasing a pain&lt;/li&gt;
&lt;li&gt;A significant bug was fixed, making tests on the previous versions mostly irrelevant&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Once you introduce such a change to your code, you want people to know about it, and you want to stop wasting cycles on it.&lt;/p&gt;

&lt;p&gt;To achieve this goal, we created a required-commit mechanism in our CI. For the CI to work, the required-commit must be an ancestor of the current commit. If it isn't - the CI fails with a descriptive error &amp;amp; instructions for fixing the issue.&lt;/p&gt;

&lt;p&gt;Once we have a new required-commit, we inform all developers in a dedicated Slack channel and update the CI to match. This ensures that even if a developer misses the notification on Slack, the CI will let them know what needs to be done.&lt;/p&gt;

&lt;p&gt;The solution consists of a simple CI job:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;required-commit&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;only&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;refs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;merge_requests&lt;/span&gt;
  &lt;span class="na"&gt;script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;apt-get update&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
      &lt;span class="s"&gt;if ! git merge-base --is-ancestor ${REQUIRED_COMMIT:-HEAD} HEAD ; then&lt;/span&gt;
        &lt;span class="s"&gt;echo&lt;/span&gt;
        &lt;span class="s"&gt;echo&lt;/span&gt;
        &lt;span class="s"&gt;echo "============================="&lt;/span&gt;
        &lt;span class="s"&gt;echo "#      Rebase Required      #"&lt;/span&gt;
        &lt;span class="s"&gt;echo "============================="&lt;/span&gt;
        &lt;span class="s"&gt;echo&lt;/span&gt;
        &lt;span class="s"&gt;echo "Your base commit is out of date."&lt;/span&gt;
        &lt;span class="s"&gt;echo "Please update to ${REQUIRED_COMMIT} or later."&lt;/span&gt;
        &lt;span class="s"&gt;echo "The easiest fix is to rebase-onto or merge-from origin/main."&lt;/span&gt;
        &lt;span class="s"&gt;echo&lt;/span&gt;
        &lt;span class="s"&gt;echo&lt;/span&gt;
        &lt;span class="s"&gt;exit 1&lt;/span&gt;
      &lt;span class="s"&gt;fi&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And a custom variable defined in the CI settings (see &lt;a href="https://docs.gitlab.com/ee/ci/variables/#create-a-custom-variable-in-the-ui"&gt;Create a custom variable in the UI&lt;/a&gt;):&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s---nnwBuRK--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/yndzgg9l11khc1oiokjz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s---nnwBuRK--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/yndzgg9l11khc1oiokjz.png" alt="alt text" width="771" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Conditionally Building Job Docker Images
&lt;/h2&gt;

&lt;p&gt;Some of our code is deployed via Docker images. As such - we want our CI to build and test those images. Some tests require running a Docker container and communicating with it, but some tests (especially unit- and integration-tests) are easier to run inside the said containers. To accommodate the latter, we use our Docker images as the base images for the CI test jobs.&lt;/p&gt;

&lt;p&gt;This is easy enough to do in the CI. In our case, however, building the Docker images takes a very long time. In trying to reduce this time, we split our build into two parts. The first - a long compilation phase, building some rarely-changing code; the second - installation of our fast-changing Python code &amp;amp; all relevant dependencies.&lt;/p&gt;

&lt;p&gt;Noticing the split between the fast-changing and rarely-changing parts of our build, we decided to split it in half, only building the first part when there's an actual change to it.&lt;/p&gt;

&lt;p&gt;To do that, however, we have to conditionally build the Docker image for the first half, and in the second half use either the preexisting first half or the newly built one.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Solution - Build, Proxy, Promote
&lt;/h3&gt;

&lt;p&gt;Our solution uses a model consisting of multiple CI jobs handling different parts.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Build&lt;/strong&gt; jobs - responsible for building docker images. Either conditionally (for the first part) or consistently (for the second part).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Proxy&lt;/strong&gt; jobs - responsible for handling the conditional nature of the build jobs, providing the next job with the relevant tag for the Docker images - either &lt;code&gt;:latest&lt;/code&gt; or the current commit.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Promote&lt;/strong&gt; jobs - responsible for tagging the newly built images with &lt;code&gt;:latest&lt;/code&gt; and pushing them. They run last.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;For our use-case, we used the following setup:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Conditional &lt;strong&gt;Build&lt;/strong&gt; job to build the rarely-changing code&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Proxy&lt;/strong&gt; job to yield the relevant tags&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Build&lt;/strong&gt; job to build &amp;amp; install the fast-changing code&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Test&lt;/strong&gt; job, to test the newly build code&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Promote&lt;/strong&gt; job, pushing the newly build images as &lt;code&gt;:latest&lt;/code&gt; if the tests passed&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;To implement it, we created the following &lt;code&gt;.yml&lt;/code&gt; configuration, representing the build-proxy-promote model, and used &lt;a href="https://docs.gitlab.com/ee/ci/yaml/#includefile"&gt;&lt;code&gt;include:file&lt;/code&gt;&lt;/a&gt; to bring it into our &lt;code&gt;.gitlab-ci.yml&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# This file allows creating a prebuild-proxy-(build)-promote workflow with ease.  &lt;/span&gt;
&lt;span class="c1"&gt;#  &lt;/span&gt;
&lt;span class="c1"&gt;# The idea is that that in the prebuild step we build less-frequently-changed  &lt;/span&gt;
&lt;span class="c1"&gt;# docker images than in the build step. This allows us to significantly speed  &lt;/span&gt;
&lt;span class="c1"&gt;# up CI times.  &lt;/span&gt;
&lt;span class="c1"&gt;#  &lt;/span&gt;
&lt;span class="c1"&gt;# Setting Up  &lt;/span&gt;
&lt;span class="c1"&gt;# ==========  &lt;/span&gt;
&lt;span class="c1"&gt;#  &lt;/span&gt;
&lt;span class="c1"&gt;# A basic setup consists of the following:  &lt;/span&gt;
&lt;span class="c1"&gt;#  &lt;/span&gt;
&lt;span class="c1"&gt;# 1\. Prebuild (extends .bpp:build)  - build docker images if relevant files changed  &lt;/span&gt;
&lt;span class="c1"&gt;# 2\. Proxy (extends .bpp:proxy) - allows the rest of the CI to know whether Prebuild created new images or not  &lt;/span&gt;
&lt;span class="c1"&gt;# 3\. Build [Optional] (extends .bpp:build) - builds extra, more-frequently-changing images.  &lt;/span&gt;
&lt;span class="c1"&gt;#                                             This is not a conditional step!  &lt;/span&gt;
&lt;span class="c1"&gt;# 4\. Use (custom step) - here we actually use the images we created!  &lt;/span&gt;
&lt;span class="c1"&gt;# 5\. Promote (extends .bpp:promote) - if required, pushes the newly built images to the project's repository.  &lt;/span&gt;
&lt;span class="c1"&gt;#  &lt;/span&gt;
&lt;span class="c1"&gt;# These 5 steps should be in 5 different, consecutive stages for things to work.  &lt;/span&gt;
&lt;span class="c1"&gt;# The prebuild step, being conditional, should not have any other step requiring it.  &lt;/span&gt;
&lt;span class="c1"&gt;# All other steps (that need the prebuilt images) should require the proxy step instead,  &lt;/span&gt;
&lt;span class="c1"&gt;# and use the ${PROXY_TAG} to as a label to the relevant docker images.&lt;/span&gt;


&lt;span class="s"&gt;.bpp:build:&lt;/span&gt;
  &lt;span class="s"&gt;variables&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;
    &lt;span class="c1"&gt;# The names of all the docker images we want to pull from our registry&lt;/span&gt;
    &lt;span class="na"&gt;TO_PULL&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;
    &lt;span class="c1"&gt;# The tag to use for pulling the images. This will usually be ${PROXY_TAG}&lt;/span&gt;
    &lt;span class="na"&gt;PULL_TAG&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;
    &lt;span class="c1"&gt;# The name of the image and path of the dockerfile for building docker images.&lt;/span&gt;
    &lt;span class="c1"&gt;# The root path for the dockers will be the root of the project&lt;/span&gt;
    &lt;span class="c1"&gt;# Format the variable as follows:&lt;/span&gt;
    &lt;span class="c1"&gt;#&lt;/span&gt;
    &lt;span class="c1"&gt;#     &amp;gt;-&lt;/span&gt;
    &lt;span class="c1"&gt;#       "some_name the/relevant/path/Dockerfile"&lt;/span&gt;
    &lt;span class="c1"&gt;#       "some_other_name another/relevant/path/Dockerfile"&lt;/span&gt;
    &lt;span class="c1"&gt;#&lt;/span&gt;
    &lt;span class="c1"&gt;# Note that the quotes are significant!&lt;/span&gt;
    &lt;span class="na"&gt;TO_BUILD&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;
    &lt;span class="c1"&gt;# The names of the images we want to push.&lt;/span&gt;
    &lt;span class="c1"&gt;# They will all be pushed with the ${CI_COMMIT_SHA} tag.&lt;/span&gt;
    &lt;span class="na"&gt;TO_PUSH&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;
&lt;span class="err"&gt;  &lt;/span&gt;&lt;span class="na"&gt;script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;docker login -u ${CI_REGISTRY_USER} -p ${CI_REGISTRY_PASSWORD} ${CI_REGISTRY_IMAGE}&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;export DOCKER_BUILDKIT=1&lt;/span&gt; &lt;span class="c1"&gt;# This cannot be in the `variables` field since users overwrite it.&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
      &lt;span class="s"&gt;for IMAGE_NAME in ${TO_PULL}&lt;/span&gt;
      &lt;span class="s"&gt;do&lt;/span&gt;
          &lt;span class="s"&gt;echo "***********************************"&lt;/span&gt;
          &lt;span class="s"&gt;echo "Pulling ${IMAGE_NAME}"&lt;/span&gt;
          &lt;span class="s"&gt;echo "-----------------------------------"&lt;/span&gt;
          &lt;span class="s"&gt;echo "docker pull ${CI_REGISTRY_IMAGE}/${IMAGE_NAME}:${PULL_TAG}"&lt;/span&gt;
          &lt;span class="s"&gt;echo "DOCKER_BUILDKIT=1 docker tag \&lt;/span&gt;
                &lt;span class="s"&gt;${CI_REGISTRY_IMAGE}/${IMAGE_NAME}:${PULL_TAG} \&lt;/span&gt;
                &lt;span class="s"&gt;${CI_REGISTRY_IMAGE}/${IMAGE_NAME}:latest"&lt;/span&gt;
          &lt;span class="s"&gt;echo "***********************************"&lt;/span&gt;
          &lt;span class="s"&gt;docker pull ${CI_REGISTRY_IMAGE}/${IMAGE_NAME}:${PULL_TAG}&lt;/span&gt;
          &lt;span class="s"&gt;docker tag \&lt;/span&gt;
              &lt;span class="s"&gt;${CI_REGISTRY_IMAGE}/${IMAGE_NAME}:${PULL_TAG} \&lt;/span&gt;
              &lt;span class="s"&gt;${CI_REGISTRY_IMAGE}/${IMAGE_NAME}:latest&lt;/span&gt;
      &lt;span class="s"&gt;done&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
      &lt;span class="s"&gt;eval "ARRAY=($TO_BUILD)"&lt;/span&gt;
      &lt;span class="s"&gt;for ITEM in "${ARRAY[@]}"&lt;/span&gt;
      &lt;span class="s"&gt;do&lt;/span&gt;
          &lt;span class="s"&gt;MY_NAME=${ITEM% *}&lt;/span&gt;
          &lt;span class="s"&gt;MY_PATH=${ITEM#* }&lt;/span&gt;
          &lt;span class="s"&gt;echo "***********************************"&lt;/span&gt;
          &lt;span class="s"&gt;echo "Building ${MY_NAME} from ${MY_PATH}"&lt;/span&gt;
          &lt;span class="s"&gt;echo "-----------------------------------"&lt;/span&gt;
          &lt;span class="s"&gt;echo "DOCKER_BUILDKIT=1 docker build \&lt;/span&gt;
              &lt;span class="s"&gt;--build-arg BUILDKIT_INLINE_CACHE=1 \&lt;/span&gt;
              &lt;span class="s"&gt;-t ${CI_REGISTRY_IMAGE}/${MY_NAME} \&lt;/span&gt;
              &lt;span class="s"&gt;-t ${CI_REGISTRY_IMAGE}/${MY_NAME}:${CI_COMMIT_SHA} \&lt;/span&gt;
              &lt;span class="s"&gt;-f ${MY_PATH} \&lt;/span&gt;
              &lt;span class="s"&gt;--label "commit_sha=${CI_COMMIT_SHA}" \&lt;/span&gt;
              &lt;span class="s"&gt;."&lt;/span&gt;
          &lt;span class="s"&gt;echo "***********************************"&lt;/span&gt;
          &lt;span class="s"&gt;docker build \&lt;/span&gt;
              &lt;span class="s"&gt;--build-arg BUILDKIT_INLINE_CACHE=1 \&lt;/span&gt;
              &lt;span class="s"&gt;-t ${CI_REGISTRY_IMAGE}/${MY_NAME} \&lt;/span&gt;
              &lt;span class="s"&gt;-t ${CI_REGISTRY_IMAGE}/${MY_NAME}:${CI_COMMIT_SHA} \&lt;/span&gt;
              &lt;span class="s"&gt;-f ${MY_PATH} \&lt;/span&gt;
              &lt;span class="s"&gt;--label "commit_sha=${CI_COMMIT_SHA}" \&lt;/span&gt;
              &lt;span class="s"&gt;.&lt;/span&gt;
      &lt;span class="s"&gt;done&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
      &lt;span class="s"&gt;for IMAGE_NAME in $TO_PUSH&lt;/span&gt;
      &lt;span class="s"&gt;do&lt;/span&gt;
          &lt;span class="s"&gt;echo "***********************************"&lt;/span&gt;
          &lt;span class="s"&gt;echo "Pushing ${IMAGE_NAME}"&lt;/span&gt;
          &lt;span class="s"&gt;echo "-----------------------------------"&lt;/span&gt;
          &lt;span class="s"&gt;echo "DOCKER_BUILDKIT=1 docker push ${CI_REGISTRY_IMAGE}/${IMAGE_NAME}:${CI_COMMIT_SHA}"&lt;/span&gt;
          &lt;span class="s"&gt;echo "***********************************"&lt;/span&gt;
          &lt;span class="s"&gt;docker push ${CI_REGISTRY_IMAGE}/${IMAGE_NAME}:${CI_COMMIT_SHA}&lt;/span&gt;
      &lt;span class="s"&gt;done&lt;/span&gt;


&lt;span class="s"&gt;.bpp:proxy:&lt;/span&gt;
  &lt;span class="s"&gt;variables&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;
    &lt;span class="c1"&gt;# The names of jobs we want to proxy - if any of them succeeded, we proxy.&lt;/span&gt;
    &lt;span class="na"&gt;BUILD_JOBS&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;
&lt;span class="err"&gt;  &lt;/span&gt;&lt;span class="na"&gt;script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;PROXY_TAG=latest&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;apt-get -qq update&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;apt-get -qq install jq&lt;/span&gt;
    &lt;span class="c1"&gt;# Get the successful jobs for the current pipeline&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="pi"&gt;&amp;gt;-&lt;/span&gt;
      &lt;span class="s"&gt;curl&lt;/span&gt;
      &lt;span class="s"&gt;--header "PRIVATE-TOKEN:${GITLAB_TOKEN}"&lt;/span&gt;
      &lt;span class="s"&gt;"${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/pipelines/${CI_PIPELINE_ID}/jobs?scope[]=success"&lt;/span&gt;
      &lt;span class="s"&gt;&amp;gt; jobs.json&lt;/span&gt;
    &lt;span class="c1"&gt;# Compare the job names from the pipeline with the provided job names&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;EXECUTED=$(comm -12 &amp;lt;(jq -r '.[].name' jobs.json | sort) &amp;lt;(echo ${BUILD_JOBS} | tr ' ' '\n' | sort))&lt;/span&gt;
    &lt;span class="c1"&gt;# If a build job was executed, we need to set the proxy tag to the current commit sha.&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
      &lt;span class="s"&gt;if [ ! -z "$EXECUTED" ]&lt;/span&gt;
      &lt;span class="s"&gt;then&lt;/span&gt;
          &lt;span class="s"&gt;PROXY_TAG=${CI_COMMIT_SHA}&lt;/span&gt;
      &lt;span class="s"&gt;fi&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;echo "PROXY_TAG=${PROXY_TAG}" &amp;gt;&amp;gt; deploy.env&lt;/span&gt;
    &lt;span class="c1"&gt;# Print out the proxy tag - for debug purposes&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;echo "PROXY_TAG=${PROXY_TAG}"&lt;/span&gt;
  &lt;span class="na"&gt;artifacts&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="c1"&gt;# To get the proxy tag, you need to get the artifacts from this job.&lt;/span&gt;
    &lt;span class="c1"&gt;# The proxy tag will be ${PROXY_TAG}&lt;/span&gt;
    &lt;span class="na"&gt;reports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;dotenv&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;deploy.env&lt;/span&gt;


&lt;span class="s"&gt;.bpp:promote:&lt;/span&gt;
  &lt;span class="s"&gt;variables&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;
    &lt;span class="c1"&gt;# The names of the images you wish to promote.&lt;/span&gt;
    &lt;span class="c1"&gt;# They need to have been built &amp;amp; pushed by a previous build step.&lt;/span&gt;
    &lt;span class="na"&gt;TO_PROMOTE&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;
&lt;span class="err"&gt;  &lt;/span&gt;&lt;span class="na"&gt;script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
      &lt;span class="s"&gt;if [ "${PROXY_TAG}" = "latest" ]; then&lt;/span&gt;
          &lt;span class="s"&gt;echo "Nothing to promote."&lt;/span&gt;
      &lt;span class="s"&gt;else&lt;/span&gt;
          &lt;span class="s"&gt;echo "Promoting docker image."&lt;/span&gt;
          &lt;span class="s"&gt;docker login -u ${CI_REGISTRY_USER} -p ${CI_REGISTRY_PASSWORD} ${CI_REGISTRY_IMAGE}&lt;/span&gt;

          &lt;span class="s"&gt;for IMAGE in ${TO_PROMOTE} ; do&lt;/span&gt;
              &lt;span class="s"&gt;docker pull ${CI_REGISTRY_IMAGE}/${IMAGE}:${CI_COMMIT_SHA}&lt;/span&gt;
              &lt;span class="s"&gt;docker tag ${CI_REGISTRY_IMAGE}/${IMAGE}:${CI_COMMIT_SHA} ${CI_REGISTRY_IMAGE}/${IMAGE}:latest&lt;/span&gt;
              &lt;span class="s"&gt;docker push ${CI_REGISTRY_IMAGE}/${IMAGE}:latest&lt;/span&gt;
          &lt;span class="s"&gt;done&lt;/span&gt;
      &lt;span class="s"&gt;fi&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>devops</category>
      <category>git</category>
      <category>gitlab</category>
      <category>cicd</category>
    </item>
    <item>
      <title>Finding a memory-leak in my Python code</title>
      <dc:creator>Tamir Bahar</dc:creator>
      <pubDate>Sat, 30 Jan 2021 15:33:26 +0000</pubDate>
      <link>https://forem.com/tmr232/finding-a-memory-leak-in-my-python-code-j73</link>
      <guid>https://forem.com/tmr232/finding-a-memory-leak-in-my-python-code-j73</guid>
      <description>&lt;p&gt;Last week I had to fix a memory leak in a Python program for the first time. A long running process started eating too much RAM (only ~20GB to much) and the friendly OOM Killer had to step in and terminate this. Since this kept happening, I had to go ahead and fix the issue.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 1 - Reproduction
&lt;/h2&gt;

&lt;p&gt;As with every bug, before you can reliably fix it, you must reproduce it.&lt;/p&gt;

&lt;p&gt;Now, while I had a reliable reproduction (after all, the process had regular dates with the OOM Killer), 3 days isn't the best cycle time when you wanna solve a bug. So into the code we go.&lt;/p&gt;

&lt;p&gt;The main idea is to start with the main loop, and try to narrow down the code that is must run for the leak to manifest. The process involves some educated guesses (where are the likely memory and allocation hogs in your process? What parts are likely to leak? Do you have any code that requires cleanup?), waiting, frustration, and tools.&lt;/p&gt;

&lt;h3&gt;
  
  
  tracemalloc
&lt;/h3&gt;

&lt;p&gt;While each developer and codebase have their own unique guesses and frustrations, good tooling applies more widely. For this part, I used Python's &lt;a href="https://docs.python.org/3/library/tracemalloc.html"&gt;tracemalloc module&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;Among other things, &lt;code&gt;tracemalloc&lt;/code&gt; allows tracking memory usage between 2 points in your code in a very low-overhead manner.&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;tracemalloc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="c1"&gt;# Start the memory trace
&lt;/span&gt;
&lt;span class="n"&gt;code_suspected_of_leak&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="n"&gt;current&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;peak&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;tracemalloc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get_traced_memory&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="c1"&gt;# Get memory stats
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After running this code, &lt;code&gt;peak&lt;/code&gt; will hold the peak-memory-usage during the trace period, and &lt;code&gt;current&lt;/code&gt; will hold the difference from the start of the trace to the current state. You should expect &lt;code&gt;current&lt;/code&gt; to be non-zero. But if it goes too high - your code is probably leaking.&lt;/p&gt;

&lt;p&gt;By placing such traces around suspect pieces of our code, we can find which parts are leaking. Just remember - only do this with functions that are expected to retain no state. If a function mutates an external object, or is a member function, it is very to exhibit changes in memory usage.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 2 - Triage
&lt;/h2&gt;

&lt;p&gt;Once we have a reproduction (that hopefully takes a relatively short amount of time), we want to find the leaking code. We can try and keep narrowing our measured code down until we find the relevant line, but the deeper we go, the harder it is to separate the leak from normal execution.&lt;/p&gt;

&lt;p&gt;So at this point, we'd like to look into the allocated memory, and see which objects are there when they shouldn't be.&lt;/p&gt;

&lt;h3&gt;
  
  
  pympler
&lt;/h3&gt;

&lt;p&gt;For inspecting the objects in a Python process, I recommend using &lt;a href="https://pympler.readthedocs.io/en/latest/"&gt;&lt;code&gt;pympler&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Pympler is a development tool to measure, monitor and analyze the memory behavior of Python objects in a running Python application.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;We're going to use it to do 2 things.&lt;/p&gt;

&lt;h4&gt;
  
  
  Inspecting Allocated Objects
&lt;/h4&gt;

&lt;p&gt;First, we're going to use &lt;code&gt;pympler&lt;/code&gt; to show us which objects were allocated during our repro &amp;amp; are still allocated.&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="nn"&gt;pympler&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;tracker&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;muppy&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;refbrowser&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;functools&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;lru_cache&lt;/span&gt;

&lt;span class="c1"&gt;# Naive code to trigger a leak
&lt;/span&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Value&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;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;__repr__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s"&gt;"Value(&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_value&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;)"&lt;/span&gt;


&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;lru_cache&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;maxsize&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;100&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;get_value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;Value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&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;code_suspected_of_leak&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;get_value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

&lt;span class="c1"&gt;# Measuring code
&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;tr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;tracker&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SummaryTracker&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="n"&gt;code_suspected_of_leak&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="n"&gt;tr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;print_diff&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once we run this, we get a nice table showing us a summary of objects created and destroyed:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;                  types |   # objects |   total size
======================= | =========== | ============
                   list |        4892 |    500.59 KB
                    str |        4887 |    341.45 KB
                    int |        1053 |     28.79 KB
                   dict |          13 |      1.90 KB
         __main__.Value |          10 |    640     B
  function (store_info) |           1 |    144     B
                   cell |           2 |    112     B
                weakref |           1 |     88     B
                  tuple |          -8 |   -680     B
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you can see - there are quite a few primitive objects generated, and also some &lt;code&gt;__main__.Value&lt;/code&gt; objects. In my experience, primitives are harder to track, as they lack meaning in the code. Your own types, however, are usually only used in certain parts of the codebase, making them easier to make sense of.&lt;/p&gt;

&lt;p&gt;Now that we see that we have 10 new &lt;code&gt;Value&lt;/code&gt; objects, it is time to figure out who's holding them in memory.&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;output_function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;o&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;type&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;o&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

&lt;span class="n"&gt;all_objects&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;muppy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get_objects&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;root&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;muppy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;all_objects&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Value&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="n"&gt;cb&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;refbrowser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ConsoleBrowser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;root&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;maxdepth&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;str_func&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;output_function&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;cb&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;print_tree&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This'll print the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;class '__main__.Value'&amp;gt;-+-&amp;lt;class 'list'&amp;gt;
                         +-&amp;lt;class 'functools._lru_cache_wrapper'&amp;gt;-+-&amp;lt;class 'list'&amp;gt;
                                                                  +-&amp;lt;class 'dict'&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Giving away the issue - the &lt;code&gt;lru_cache&lt;/code&gt; is keeping our &lt;code&gt;Value&lt;/code&gt; objects. Just as designed...&lt;/p&gt;

&lt;p&gt;I know this looks like a bit of a contrived example, but the &lt;code&gt;lru_cache&lt;/code&gt; keeping objects in memory was exactly the issue I had. It was just buried under far more code. &lt;/p&gt;

&lt;h2&gt;
  
  
  Step 3 - Solution
&lt;/h2&gt;

&lt;p&gt;Currently, I use the ugliest solution I can imagine - functions decorated with &lt;code&gt;lru_cache&lt;/code&gt; have a &lt;code&gt;cache_clear()&lt;/code&gt; method, and I'm calling that at specific places in my code. It's ugly, but it works.&lt;/p&gt;

&lt;p&gt;A cleaner solution would require dedicated caches &amp;amp; better cleanup mechanisms. You can read a relevant discussion &lt;a href="https://bugs.python.org/issue19859"&gt;here&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>python</category>
      <category>bugs</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>TIL Python attribute lookup order is tricky</title>
      <dc:creator>Tamir Bahar</dc:creator>
      <pubDate>Wed, 03 Jun 2020 18:59:53 +0000</pubDate>
      <link>https://forem.com/tmr232/til-python-attribute-lookup-order-is-tricky-5ejb</link>
      <guid>https://forem.com/tmr232/til-python-attribute-lookup-order-is-tricky-5ejb</guid>
      <description>&lt;p&gt;&lt;em&gt;This post is brought to you in the spirit of converting tweetstorms to blogposts.&lt;br&gt;
&lt;a href="https://twitter.com/tmr232/status/1268244709723582467"&gt;to the tweetstorm&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Surprise! 🎁
&lt;/h2&gt;

&lt;p&gt;In Python, if property access raises AttributeError, and the class implemented &lt;strong&gt;getattr&lt;/strong&gt;, it will get called with the property name.&lt;br&gt;
This results in some very cryptic errors.&lt;/p&gt;

&lt;p&gt;If you run the following code (&lt;a href="https://repl.it/repls/PresentBitterUnit"&gt;repl&lt;/a&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;class&lt;/span&gt; &lt;span class="nc"&gt;Thing&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Thing"&lt;/span&gt;


&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;NameProvider&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;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_name&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;nam&lt;/span&gt;


&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ThingWrapper&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;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;thing&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;name_provider&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;thing&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;thing&lt;/span&gt;
        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name_provider&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;name_provider&lt;/span&gt;

    &lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="nb"&gt;property&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;name&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name_provider&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get_name&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;__getattr__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;getattr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;thing&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;name&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;main&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;thing&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Thing&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;name_provider&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;NameProvider&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"Not Thing"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;thing_wrapper&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ThingWrapper&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;thing&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;name_provider&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;thing&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;thing_wrapper&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&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;__name__&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s"&gt;'__main__'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You'll get a surprising result:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;You might have expected &lt;code&gt;"Not Thing"&lt;/code&gt; as the second line, or maybe an exception to be raised from &lt;code&gt;NameProvider.get_name()&lt;/code&gt; due to the typo there (&lt;code&gt;self.nam&lt;/code&gt; instead of &lt;code&gt;self.name&lt;/code&gt;). But instead, we got the name attribute from our &lt;code&gt;Thing&lt;/code&gt; instance.&lt;/p&gt;

&lt;h2&gt;
  
  
  Analysis 🔎
&lt;/h2&gt;

&lt;p&gt;If you've every used &lt;code&gt;__getattr__()&lt;/code&gt; you know that it is called when the named attribute was not found using other lookup mechanisms. That said, it might not be clear to you that this includes properties raising &lt;code&gt;AttributeError&lt;/code&gt; exceptions. It definitely wasn't clear to me.&lt;/p&gt;

&lt;p&gt;That is, it was unclear to me despite being clearly stated in the &lt;a href="https://docs.python.org/3/reference/datamodel.html#object.__getattr__"&gt;documentation for &lt;strong&gt;getattr&lt;/strong&gt;()&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;object.__getattr__(self, name)&lt;/code&gt;&lt;/strong&gt;&lt;br&gt;
Called when the default attribute access fails with an &lt;code&gt;AttributeError&lt;/code&gt; (either &lt;code&gt;__getattribute__()&lt;/code&gt; raises an &lt;code&gt;AttributeError&lt;/code&gt; because name is not an instance attribute or an attribute in the class tree for self; or &lt;code&gt;__get__()&lt;/code&gt; of a name property raises &lt;code&gt;AttributeError&lt;/code&gt;). This method should either return the (computed) attribute value or raise an &lt;code&gt;AttributeError&lt;/code&gt; exception.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Beside being surprising, there are 2 main issues here:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Any code down the stack from the property can effectively change attribute lookup for the class by throwing an &lt;code&gt;AttributeError&lt;/code&gt;. In the above example - a typo in &lt;code&gt;NameProvider&lt;/code&gt; caused an attribute to be taken from &lt;code&gt;Thing&lt;/code&gt; instead, against the programmer's obvious intention.&lt;/li&gt;
&lt;li&gt;The exception is silenced. There is no way for the programmer to catch the exception outside the property getter. This makes the errors &lt;em&gt;very&lt;/em&gt; hard to track down. This also means that whenever you add &lt;code&gt;__getattr__()&lt;/code&gt; to a class, you're silencing all &lt;code&gt;AttributeError&lt;/code&gt; exceptions that were previously thrown from properties.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Like anything in Python, you can hack around the issue. In this case - with fancy decorators!&lt;/p&gt;

&lt;h2&gt;
  
  
  Solution? 🐍
&lt;/h2&gt;

&lt;p&gt;Consider the following code (&lt;a href="https://repl.it/repls/IntentionalIgnorantLinuxpc"&gt;repl&lt;/a&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;class&lt;/span&gt; &lt;span class="nc"&gt;ExceptionCatcher&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;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;
        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;exception&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;__call__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="nb"&gt;Exception&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;exception&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;
            &lt;span class="k"&gt;raise&lt;/span&gt;
        &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;exception&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;store_exception&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;ExceptionCatcher&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;f&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;load_exception&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;f&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;_raise_property_exception&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;instance&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;class_attr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;getattr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;instance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;__class__&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="nb"&gt;isinstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;class_attr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;property&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
                &lt;span class="k"&gt;return&lt;/span&gt;
            &lt;span class="n"&gt;exception&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;class_attr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fget&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;exception&lt;/span&gt;
        &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="nb"&gt;AttributeError&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt;

        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;exception&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="n"&gt;exception&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;_wrapper&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;_raise_property_exception&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;_wrapper&lt;/span&gt;


&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ThingWrapper&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;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;thing&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;name_provider&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;thing&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;thing&lt;/span&gt;
        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name_provider&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;name_provider&lt;/span&gt;

    &lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="nb"&gt;property&lt;/span&gt;
    &lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;store_exception&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;name&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name_provider&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get_name&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;load_exception&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;__getattr__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;getattr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;thing&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you run this version, you'll get the following exception:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;This matches our expectations far better. &lt;/p&gt;

&lt;p&gt;This result is achieved in two steps. First, we store all the exceptions thrown from &lt;code&gt;name()&lt;/code&gt; so that we can throw them again if needed. Then, before calling &lt;code&gt;__getattr__()&lt;/code&gt;, we check if we got there due to a property raising an exception. If we did - we just re-raise that exception.&lt;/p&gt;

&lt;p&gt;The rest is implementation details, and I probably missed something there (you might notice that I corrected a bug when converting the tweets to this post - in the previous version, I forget to reset the exception storage after successful property retrieval).&lt;/p&gt;

&lt;p&gt;While this solution works, and may be useful for detecting similar bugs, I would probably avoid using it in production code. Instead, I'd be happy to have some standard Python construct to provide this functionality. &lt;/p&gt;

</description>
      <category>todayilearned</category>
      <category>python</category>
    </item>
    <item>
      <title>Snake Eyes: Extension Methods</title>
      <dc:creator>Tamir Bahar</dc:creator>
      <pubDate>Thu, 05 Mar 2020 22:24:49 +0000</pubDate>
      <link>https://forem.com/tmr232/snake-eyes-extension-methods-1jb</link>
      <guid>https://forem.com/tmr232/snake-eyes-extension-methods-1jb</guid>
      <description>&lt;p&gt;Today we set out to implement a feature I saw and liked in Kotlin - &lt;a href="https://kotlinlang.org/docs/reference/extensions.html"&gt;Extension Methods&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;You can follow along with working code samples &lt;a href="https://repl.it/@TamirBahar/python-extension-methods"&gt;here&lt;/a&gt;, or get the code &lt;a href="https://github.com/tmr232/python-extension-methods"&gt;here&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Extension methods are a nice piece of syntactic-sugar that allow you to define free-functions and call them like instance methods. In Kotlin, it looks something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nc"&gt;Square&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;draw&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;drawSquare&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// ...&lt;/span&gt;

&lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;square&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;getSquare&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;square&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;draw&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, since they are free, static functions, they follow the same rules. They are not part of the class, nor have access to private members. And they can only be called in a scope where they are visible. Adding them in your code does not affect other code. Additionally, true member functions, if they exist, take precedence over extension methods (this is especially important with generic extension methods).&lt;/p&gt;

&lt;p&gt;In our code today, we'll try to mimic the features of extension methods as closely as possible. We'll use the following syntax:&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="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;extend&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Square&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;draw&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;square&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;draw_square&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;square&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For extension methods, and the following implementation of &lt;code&gt;Square&lt;/code&gt; in our code throughout:&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="nn"&gt;dataclasses&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;dataclass&lt;/span&gt;

&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;dataclass&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Square&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;length&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Monkey Patching 🙈
&lt;/h2&gt;

&lt;p&gt;Python is a very dynamic language. Among other things, it allows us to change the attributes of (non-builtin) types at run-time. This means that we can extend our &lt;code&gt;Square&lt;/code&gt; class by adding a &lt;code&gt;draw&lt;/code&gt; method to it at run-time.&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;Square&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;draw&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;draw_square&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We're now free to call &lt;code&gt;square.draw()&lt;/code&gt;. Before we discuss the draw-backs, let's implement it with the syntax we defined:&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;monkey_extend&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cls&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;f&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="nb"&gt;setattr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cls&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;__name__&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;_decorator&lt;/span&gt;

&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;monkey_extend&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Square&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;draw&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;square&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;draw_square&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;square&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's go over this. &lt;code&gt;monkey_extend&lt;/code&gt; is a decorator with arguments. This is a common pattern where we use a decorator factory (&lt;code&gt;monkey_extend&lt;/code&gt;) to create a new decorator (&lt;code&gt;_decorator&lt;/code&gt;) as a closure, giving it access to the parameters passed to the factory (&lt;code&gt;cls&lt;/code&gt;). Then, in the core of the decorator, we use &lt;code&gt;setattr&lt;/code&gt; to do our monkey-patching.&lt;/p&gt;

&lt;p&gt;While this works, it has several issues:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Scope - once set, it can be used with any &lt;code&gt;Square&lt;/code&gt; in any scope&lt;/li&gt;
&lt;li&gt;Precedence - it will override any existing &lt;code&gt;Square.draw&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Dealing with precedence is easy (using &lt;code&gt;hasattr&lt;/code&gt; to check for existing &lt;code&gt;.draw&lt;/code&gt;) so we'll focus on the scoping first.&lt;/p&gt;

&lt;h2&gt;
  
  
  Dynamic Attribute Lookup ✨
&lt;/h2&gt;

&lt;p&gt;The first thing we know is that we need our new attribute to be there in some cases, and be gone in others - we need dynamic resolution. To do that, we'll use &lt;a href="https://docs.python.org/3/reference/datamodel.html#object.__getattr__"&gt;&lt;code&gt;__getattr__&lt;/code&gt;&lt;/a&gt;. In Python classes, &lt;code&gt;__getattr__&lt;/code&gt; is used in attribute lookup as a last resort, called when the other ways of looking up attributes came up empty. We'll write our &lt;code&gt;__getattr__&lt;/code&gt; along the following lines:&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;my_getattr&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="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;has_extension&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="n"&gt;name&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;AttributeError&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;is_in_scope&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&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;AttributeError&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;our_extension&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The first check, &lt;code&gt;has_extension&lt;/code&gt;, is basically checking whether the name we got matches the name of our extension method. Nothing to elaborate yet. Scoping, once again, remains the trickier part.&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;import&lt;/span&gt; &lt;span class="nn"&gt;functools&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;inspect&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;collections&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;ChainMap&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;scoped_extend&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cls&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;f&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;_getattr&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="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="c1"&gt;# (2)
&lt;/span&gt;            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;__name__&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;AttributeError&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

            &lt;span class="c1"&gt;# (3)
&lt;/span&gt;            &lt;span class="n"&gt;frame&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;inspect&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stack&lt;/span&gt;&lt;span class="p"&gt;()[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;frame&lt;/span&gt;
            &lt;span class="n"&gt;scope&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ChainMap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;frame&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;f_locals&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;frame&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;f_globals&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;scope&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;__name__&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;f&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;AttributeError&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

            &lt;span class="c1"&gt;# (4)
&lt;/span&gt;            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;functools&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;partial&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;f&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="c1"&gt;# (1)
&lt;/span&gt;        &lt;span class="n"&gt;cls&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;__getattr__&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;_getattr&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;f&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;This is a bit much, so we'll go over it in detail.&lt;/p&gt;

&lt;p&gt;As a basis, we used the same decorator-with-parameters pattern here. We have &lt;code&gt;scoped_extend&lt;/code&gt; take the class we want to extend, then return &lt;code&gt;_decorator&lt;/code&gt; to get the job done. But instead of setting the attribute we want to extend, we monkey-patch &lt;code&gt;cls&lt;/code&gt;'s &lt;code&gt;__getattr__&lt;/code&gt; to our implementation (See &lt;strong&gt;(1)&lt;/strong&gt;).  This will override any existing implementation of &lt;code&gt;__getattr__&lt;/code&gt;, but we'll get to that later. For now, we'll focus on our implementation of &lt;code&gt;__getattr__&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;In &lt;strong&gt;(2)&lt;/strong&gt; we implemented &lt;code&gt;has_extnesion&lt;/code&gt; - we simply compare the name we got to the name of our extension method. Then, in &lt;strong&gt;(3)&lt;/strong&gt;, comes some Python magic. Python allows us to inspect the running program, to see where we were called from and what variables were in scope in that code. To do that, we use the &lt;a href="https://docs.python.org/3/library/inspect.html"&gt;&lt;code&gt;inspect&lt;/code&gt;&lt;/a&gt; module. We use &lt;code&gt;inspect.stack()&lt;/code&gt; to get the call-stack for the current execution, then access the second frame (&lt;code&gt;[1]&lt;/code&gt;) to get our caller. This will be where &lt;code&gt;getattr(obj, name)&lt;/code&gt; is invoked or &lt;code&gt;obj.name&lt;/code&gt; is used. We use &lt;code&gt;.frame&lt;/code&gt; to get the execution frame, and &lt;code&gt;.f_locals&lt;/code&gt; and &lt;code&gt;f_globals&lt;/code&gt; to get the local and global variables available in that scope. They are equivalent to calling &lt;code&gt;globals()&lt;/code&gt; or &lt;code&gt;locals()&lt;/code&gt; in the relevant frame.&lt;/p&gt;

&lt;p&gt;With the scope at hand, we perform a lookup to see whether the extension method we defined is in that scope. To make sure we have our extension method, we get it by name, then ensure that it is truly our method.&lt;/p&gt;

&lt;p&gt;Finally, in &lt;strong&gt;(4)&lt;/strong&gt;, when we know our method should be active, we bind it to the instance of the extended class and return it.&lt;/p&gt;

&lt;h3&gt;
  
  
  Better Scoping
&lt;/h3&gt;

&lt;p&gt;While our scope retrieval code works, it's better to put it in a function rather than use it inline:&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;_is_in_scope&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;frame&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;inspect&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stack&lt;/span&gt;&lt;span class="p"&gt;()[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;frame&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;ChainMap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;frame&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;f_locals&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;frame&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;f_globals&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But, oh, we have to increment the stack index to &lt;code&gt;2&lt;/code&gt; since we're deeper in the callstack. This is risky. Instead, we'll use the following trick to get the frame:&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;_get_first_external_stack_frame&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;frameinfo&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;inspect&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stack&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;frameinfo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;filename&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;__file__&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;continue&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;frameinfo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;frame&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;_is_in_scope&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;frame&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;_get_first_external_stack_frame&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;ChainMap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;frame&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;f_locals&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;frame&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;f_globals&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Instead of counting the frames in our code, changing them with every change - we'll use the module system. We know that all of our scaffolding is in the same module, but the usage is not. This allows us to easily traverse the stack until we find code that does not belong in our module. &lt;em&gt;That&lt;/em&gt; is our calling code.&lt;/p&gt;

&lt;p&gt;Since you're probably wondering - yes. You need to change &lt;code&gt;_get_first_external_stack_frame()&lt;/code&gt; if you want to put it in a different module. Implementing it is left as an exercise to the reader.&lt;/p&gt;

&lt;h2&gt;
  
  
  Preserving &lt;code&gt;__getattr__&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;As mentioned before, our current implementation overrides any existing &lt;code&gt;__getattr__&lt;/code&gt; function for the class. Lucky for us, fixing it is easy:&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;no_override_extend&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cls&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;f&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;_default&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="n"&gt;_name&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;AttributeError&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

        &lt;span class="n"&gt;original_getattr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;getattr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cls&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;'__getattr__'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_default&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;_getattr&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="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;suppress&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;AttributeError&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
                &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;original_getattr&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="n"&gt;name&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;name&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;__name__&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;AttributeError&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;_is_in_scope&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;f&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;AttributeError&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;functools&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;partial&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;f&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="n"&gt;cls&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;__getattr__&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;_getattr&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;f&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;In &lt;strong&gt;(1)&lt;/strong&gt; we get the original &lt;code&gt;__getattr__&lt;/code&gt; method, to be stored for later usage. We use the &lt;code&gt;_default&lt;/code&gt; function to avoid an extra &lt;code&gt;if&lt;/code&gt; later. In &lt;strong&gt;(2)&lt;/strong&gt; we use the saved &lt;code&gt;__getattr__&lt;/code&gt;,  making sure that we only proceed to our code if it raised an &lt;code&gt;AttributeError&lt;/code&gt; exception.&lt;/p&gt;

&lt;h2&gt;
  
  
  Interlude 🐍
&lt;/h2&gt;

&lt;p&gt;With &lt;code&gt;no_override_extend&lt;/code&gt; we have our first "to-spec" implementation of extension methods. We have both scoping and precedence down. It is time to celebrate and rest. But our quest is not done yet.&lt;/p&gt;

&lt;p&gt;While our code works well for a proof-of-concept, there are still significant usability issues with it. Since the extension methods we create have nice and clean names, it is likely that we'll want to use those names for other things. Unfortunately, once we do that, we'll override the existing extension methods and they will no longer work:&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="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;extend&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Square&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;draw&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;square&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;draw_square&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;square&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;draw&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Drawing is awesome!"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# ...
&lt;/span&gt;
&lt;span class="n"&gt;square&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;draw&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;  &lt;span class="c1"&gt;# This will fail, as `draw` has been replaced in this scope.
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Indirection 🔀
&lt;/h2&gt;

&lt;p&gt;The &lt;a href="https://en.wikipedia.org/wiki/Fundamental_theorem_of_software_engineering"&gt;Fundemental Theorem of Software Engineering (FTSE)&lt;/a&gt; says that any problem can be solved by adding another level of indirection. Let's see how this applies to our problem.&lt;/p&gt;

&lt;p&gt;As mentioned in the interlude, our main issue is that of naming. Our extension method is bound to a name, and that name can be overriden in the scope that defines it. If that happens, we lose our extension method. To solve that, we'll add another level of indirection - a scope that can safely hold our extension methods and protect them from being overriden. If you read our &lt;a href="https://dev.to/tmr232/snake-eyes-scopes-and-iife-50h2"&gt;previous post&lt;/a&gt; you might recall that classes are wonderful for scopes. So we'll use a class.&lt;/p&gt;

&lt;p&gt;Our new syntax will look 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="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;extension&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ExtensionMethods&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Square&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;draw&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;draw_square&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;While we're still using a decorator, you may notice that it takes no parameters. Instead, we use the extended type as the base type for our extension class. This allows us to write the extensions like any other subclass, with standard Python syntax, and then use the decorator to install the extensions in it.&lt;/p&gt;

&lt;p&gt;Since we've already gone over the principles behind the construction of the decorator, let's jump straight to the code and focus on the differences from the previous version:&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;extension&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;scope_cls&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;_default&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="n"&gt;_name&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;AttributeError&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="c1"&gt;# (1)
&lt;/span&gt;    &lt;span class="n"&gt;cls&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;scope_cls&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;__base__&lt;/span&gt;
    &lt;span class="n"&gt;original_getattr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;getattr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cls&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;'__getattr__'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_default&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;_getattr&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="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;suppress&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;AttributeError&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;original_getattr&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="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="c1"&gt;# (2)
&lt;/span&gt;        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="nb"&gt;hasattr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;scope_cls&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;name&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;AttributeError&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

        &lt;span class="c1"&gt;# (3)
&lt;/span&gt;        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;_is_in_scope&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;scope_cls&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;AttributeError&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

        &lt;span class="c1"&gt;# (4)
&lt;/span&gt;        &lt;span class="n"&gt;f&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;getattr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;scope_cls&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;functools&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;partial&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;f&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="n"&gt;cls&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;__getattr__&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;_getattr&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;First, you can see that there is no nested decorator - only the main one. And, as we mentioned before, we use inheritance to indicate which type we're extending. So in &lt;strong&gt;(1)&lt;/strong&gt; we access the base-class of our extension class to get the class we're extending. Then, in &lt;strong&gt;(2)&lt;/strong&gt; we check whether the requested attribute exists in our extension class. As you can see, the changes are pretty simple and straight-forward. In &lt;strong&gt;(3)&lt;/strong&gt; we make the most important change - we check for the extension class in the scope, not the extension methods. This is the core of this change! And lastly, in &lt;strong&gt;(4)&lt;/strong&gt;, we get the required attribute from out extension class.&lt;/p&gt;

&lt;p&gt;And with that, we're done.&lt;/p&gt;

&lt;h2&gt;
  
  
  Final Words
&lt;/h2&gt;

&lt;p&gt;I hope you enjoyed this article. Regardless of that, I hope you never use it in production code.&lt;/p&gt;

</description>
      <category>python</category>
      <category>kotlin</category>
      <category>misguided</category>
    </item>
    <item>
      <title>Snake Eyes: Scopes and IIFE</title>
      <dc:creator>Tamir Bahar</dc:creator>
      <pubDate>Fri, 27 Dec 2019 12:09:43 +0000</pubDate>
      <link>https://forem.com/tmr232/snake-eyes-scopes-and-iife-50h2</link>
      <guid>https://forem.com/tmr232/snake-eyes-scopes-and-iife-50h2</guid>
      <description>&lt;p&gt;One of my pet peeves is taking concepts from other languages and "translating" them to Python. Not because it makes good code, but because it's a challenge and it makes me happy.&lt;/p&gt;

&lt;p&gt;This time, I've gone after two simple concepts - nested code blocks and IIFE. Both serve similar purposes, and both are missing from Python.&lt;/p&gt;

&lt;p&gt;In C++, blocks are often used to limits the lifetime of objects and keep them out of our way when we're done with them. In Python, lifetime is usually less of a concern (as we replace &lt;a href="https://en.cppreference.com/w/cpp/language/raii"&gt;RAII&lt;/a&gt; and &lt;a href="https://en.cppreference.com/w/cpp/language/destructor"&gt;destructors&lt;/a&gt; with &lt;a href="https://docs.python.org/3/reference/datamodel.html#context-managers"&gt;context-managers&lt;/a&gt;), but having variable names out of our way is desirable.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://en.wikipedia.org/wiki/Immediately_invoked_function_expression"&gt;IIFE&lt;/a&gt; offers us a bit more in terms of functionality, as it both creates a scope for our operations, and allows us to get a value from that scope. This is useful both for simpler flow control, and for easily initializing const-qualified variables.&lt;/p&gt;

&lt;p&gt;Python does not have any of those constructs. There is no way to create a nested code-block in Python (adding another level of indentation would just have it complain about unexpected-indent), and while lambdas exist, they only allow for a single expression, making them mostly irrelevant for IIFE. On the other hand, Python offers us two wonderful constructs that can be used virtually everywhere - classes and functions. &lt;/p&gt;

&lt;h2&gt;
  
  
  Classes &amp;amp; Nested Blocks 🧱🧱🧱
&lt;/h2&gt;

&lt;p&gt;In Python, both classes and functions can be nested. You can define a class inside a class, a function in a function, a class in a function or a function in a class. It is all the same. What's more - you can have flow-control in both function (well, obviously) and class bodies (meta-programming much?). Additionally, both nested functions and nested classes create new variable scopes, keeping their insides inside, and are also closures, capable of capturing values from their enclosing scopes. As such, they are the perfect tools for our language-bending shenanigans.&lt;/p&gt;

&lt;p&gt;First, nested code blocks. I offer you the following solution:&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;f&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'Classes are great for creating blocks.'&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;_&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;
        &lt;span class="k"&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="s"&gt;'y = &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'y is not defined here.'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;y&lt;/span&gt;

&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;21&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;By defining a class, we create a new scope. Inside it, we can do whatever we want, knowing that the code will get execute inline and in order, and the results will not leak into the enclosing scope. &lt;/p&gt;

&lt;p&gt;That said - there are some caveats. First, the class remains in scope, and so do all the variables defined in it. They cannot be garbage collected until the function terminates. You can verify it yourself by trying to access &lt;code&gt;_.y&lt;/code&gt; in the above example. To remedy that, we need to get rid of the class, or at least its contents. There are many ways to achieve 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="c1"&gt;# Replace the class with a bool
&lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="nb"&gt;bool&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;_&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
    &lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


&lt;span class="c1"&gt;# Replace the class with None
&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;empty&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;


&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;empty&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;_&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
    &lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


&lt;span class="c1"&gt;# Use a metaclass to delete all the variables inside the class
&lt;/span&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;BlockMeta&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;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;__new__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cls&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;bases&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;dict_&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;super&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="n"&gt;__new__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cls&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;bases&lt;/span&gt;&lt;span class="p"&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;Block&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;metaclass&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;BlockMeta&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;_&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Block&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
    &lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I am personally torn between the meta-class approach, as it is explicit and clear, and the &lt;code&gt;@bool&lt;/code&gt; approach, as it requires to additional boilerplate.&lt;/p&gt;

&lt;p&gt;The second issue with classes as blocks is that while they can be nested freely, a nested class cannot access the variables of its nesting class, rendering block-nesting moot. I do not have a solution for that at present.&lt;/p&gt;

&lt;h2&gt;
  
  
  Functions &amp;amp; IIFE 🐍🐍🐍
&lt;/h2&gt;

&lt;p&gt;With a solution for nested blocks in hand, it is time to get proper IIFE in Python. For that, we'll naturally be using function. Along with those, we'll use a function's best friend - the 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;iife&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;f&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;describe_number&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;iife&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;message&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;n&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s"&gt;'&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; is smaller than 0'&lt;/span&gt;
        &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s"&gt;'&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; is larger than 0'&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s"&gt;'&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; is 0'&lt;/span&gt;

    &lt;span class="k"&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;span class="n"&gt;describe_number&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;describe_number&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;describe_number&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Using the decorator, we immediately call the function, binding the function's name to the return value instead of the function itself. A function returning &lt;code&gt;None&lt;/code&gt; (or without a return statement) will just bind the name to &lt;code&gt;None&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;While this looks a bit more messy, it can also double as a solution for nested blocks. And unlike the class solution - it can be freely nested.&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;iife&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;f&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;block&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;f&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;f&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'Functions are great for creating blocks.'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;block&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;my_x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
        &lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;iife&lt;/span&gt;
        &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;y&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;my_x&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;

        &lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;block&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="k"&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="s"&gt;'y = &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'y is not defined here.'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;y&lt;/span&gt;


&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's it for today. I hope you had some fun.&lt;/p&gt;

</description>
      <category>python</category>
      <category>misguided</category>
      <category>funny</category>
    </item>
    <item>
      <title>Why do websites ask me where I'm from?</title>
      <dc:creator>Tamir Bahar</dc:creator>
      <pubDate>Wed, 17 Oct 2018 10:17:06 +0000</pubDate>
      <link>https://forem.com/tmr232/why-do-websites-ask-me-where-im-from-38gj</link>
      <guid>https://forem.com/tmr232/why-do-websites-ask-me-where-im-from-38gj</guid>
      <description>&lt;p&gt;Whenever I need to enter my address in a web-form, I always need to choose the country. It never defaults to the country I'm browsing from.&lt;br&gt;
This always seemed weird to me as the advertisements and localized content always know where I'm from. &lt;/p&gt;

&lt;p&gt;Why then don't websites use the same location &amp;amp; tracking info to make my job easier when filling forms?&lt;/p&gt;

</description>
      <category>discuss</category>
    </item>
    <item>
      <title>Recognizing Ducks</title>
      <dc:creator>Tamir Bahar</dc:creator>
      <pubDate>Sat, 13 Oct 2018 16:00:21 +0000</pubDate>
      <link>https://forem.com/tmr232/recognizing-ducks-n4c</link>
      <guid>https://forem.com/tmr232/recognizing-ducks-n4c</guid>
      <description>&lt;p&gt;After multiple attempts at finding a funny narrative that holds for the entire article and failing miserably, I decided to go with the technical parts alone. Enough of my colleagues found it interesting, so I guess it will hold up without the jokes.&lt;/p&gt;

&lt;p&gt;Python gives us multiple ways to check that the objects we pass to functions are of the types we expect. Each method has its advantages and disadvantages.&lt;/p&gt;

&lt;h2&gt;
  
  
  Just not caring
&lt;/h2&gt;

&lt;p&gt;The first option is naturally to not care about types - just write your code, and hope for the best.&lt;br&gt;
This is a viable method, and is often employed. It is especially fitting in short snippets or scripts you don't expect to maintain much. It just works with no overhead whatsoever.&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;poke&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;duck&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;duck&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;quack&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;duck&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;walk&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Inheritance
&lt;/h2&gt;

&lt;p&gt;Another option, as common in OOP languages, is to use inheritance. We can define an &lt;code&gt;Anas&lt;/code&gt; class, and expect all of its derivatives to be sufficiently duck-like.&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;Anas&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;quack&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&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;def&lt;/span&gt; &lt;span class="nf"&gt;walk&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&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;Duck&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Anas&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;quack&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'Quack!'&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;walk&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'Walks like duck.'&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;Mallard&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Anas&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;quack&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'Quack!'&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;walk&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'Walks like 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;poke&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;duck&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="nb"&gt;isinstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;duck&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Anas&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Interfaces
&lt;/h2&gt;

&lt;p&gt;While inheritance kinda gets the job done, a robotic duck is definitely not of the genus &lt;a href="https://en.wikipedia.org/wiki/Anas"&gt;Anas&lt;/a&gt;, while it does implement all the characteristics we care about. So instead of hierarchical inheritance, we can use interfaces.&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="nn"&gt;abc&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;ABC&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;abstractmethod&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;IDuck&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ABC&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;abstractmethod&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;quack&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&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="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;abstractmethod&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;walk&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&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;Duck&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;IDuck&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;quack&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'Quack!'&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;walk&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'Walks like duck.'&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;RoboticDuck&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;IDuck&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;quack&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'Quack!'&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;walk&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'Walks like 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;poke&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;duck&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="nb"&gt;isinstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;duck&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;IDuck&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Great. And if we don't control the types, we can always write adapters.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Duck Test
&lt;/h2&gt;

&lt;p&gt;But this is Python. We can do better.&lt;/p&gt;

&lt;p&gt;As we know, Python uses duck-typing. So we should be able to use the &lt;a href="https://en.wikipedia.org/wiki/Duck_test"&gt;Duck Test&lt;/a&gt; for types. In our example, every object implementing &lt;code&gt;quack()&lt;/code&gt; and &lt;code&gt;walk()&lt;/code&gt; is a duck. That's easy enough to check.&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;is_a_duck&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;duck&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;attr&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'quack'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;'walk'&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="nb"&gt;hasattr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;duck&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;attr&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;poke&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;duck&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;is_a_duck&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;duck&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;duck&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;quack&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;duck&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;walk&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This works. But we list the &lt;code&gt;isinstance(...)&lt;/code&gt; call. We can surely do better.&lt;/p&gt;

&lt;h2&gt;
  
  
  Metaclasses &amp;amp; Subclass Hooks
&lt;/h2&gt;

&lt;p&gt;Metaclasses are wonderful constructs. As their name may suggest, they take part in the construction of classes. They even allow us to set hooks into basic Python mechanisms, like &lt;code&gt;isinstance(...)&lt;/code&gt;, using &lt;a href="https://docs.python.org/3/library/abc.html#abc.ABCMeta.__subclasshook__"&gt;&lt;code&gt;__subclasshook__&lt;/code&gt;&lt;/a&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="nn"&gt;abc&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;ABC&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;is_a_duck&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;duck&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;attr&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'quack'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;'walk'&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="nb"&gt;hasattr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;duck&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;attr&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;DuckChecker&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ABC&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="nb"&gt;classmethod&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;__subclasshook__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cls&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;C&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;cls&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;DuckChecker&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;NotImplemented&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;is_a_duck&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;C&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;poke&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;duck&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="nb"&gt;isinstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;duck&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;DuckChecker&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;duck&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;quack&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;duck&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;walk&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And we're back in business. That said, &lt;code&gt;is_a_duck&lt;/code&gt; is still a stringly-typed mess, and gonna be very painful to maintain.&lt;/p&gt;

&lt;p&gt;Wouldn't it be nice if we could just use our &lt;code&gt;IDuck&lt;/code&gt; interface to check for duck-ness?&lt;/p&gt;

&lt;h2&gt;
  
  
  Abstract Methods, Again!
&lt;/h2&gt;

&lt;p&gt;Lucky for us - we can!&lt;/p&gt;

&lt;p&gt;Among other things, the &lt;code&gt;ABC&lt;/code&gt; parent class enumerates all &lt;code&gt;@abstractmethod&lt;/code&gt;s and stores them in the &lt;code&gt;__abstractmethods__&lt;/code&gt; member variable. This means that we can easily enumerate them in our subclass hook and check for 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="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;abc&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;ABC&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;abstractmethod&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;IDuck&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ABC&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;abstractmethod&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;quack&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&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="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;abstractmethod&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;walk&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&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="o"&gt;@&lt;/span&gt;&lt;span class="nb"&gt;classmethod&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;__subclasshook__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cls&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;C&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;cls&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;IDuck&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;NotImplemented&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;attr&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;cls&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;__abstractmethods__&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="nb"&gt;hasattr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;C&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;attr&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
                &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&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;quack&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'Quack!'&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;walk&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'Walks like a 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;poke&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;duck&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="nb"&gt;isinstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;duck&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;IDuck&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;duck&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;quack&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;duck&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;walk&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="n"&gt;poke&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Duck&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;  &lt;span class="c1"&gt;# Quack!
&lt;/span&gt;              &lt;span class="c1"&gt;# Walks like a duck.
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Awesome. Next step - separating the interface from the checking logic.&lt;/p&gt;

&lt;h2&gt;
  
  
  Protocols
&lt;/h2&gt;

&lt;p&gt;Reading through Python documentation and nomenclature, you might have seen the term "protocol" here and there. It is Python's way to call duck-typed interfaces. So you could say we just created a "protocol checker". Now, we can separate it into 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="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;abc&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;ABC&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;abstractmethod&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Protocol&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ABC&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;_is_protocol&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;
    &lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="nb"&gt;classmethod&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;__subclasshook__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cls&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;C&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;cls&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_is_protocol&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;NotImplemented&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;attr&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;cls&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;__abstractmethods__&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="nb"&gt;hasattr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;C&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;attr&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
                &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;IDuck&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Protocol&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;abstractmethod&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;quack&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&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="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;abstractmethod&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;walk&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&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 that's it. That little &lt;code&gt;_is_protocol&lt;/code&gt; flag is there for good reason. Usually, we'd check protocol-ness using &lt;code&gt;isinstance(...)&lt;/code&gt;. In this case, however, we're hooking into that mechanism and that would lead to infinite recursion.&lt;/p&gt;

&lt;p&gt;We can now use our &lt;code&gt;Protocol&lt;/code&gt; base-class freely to create new protocols as we need them, with friendly interface-like syntax. We're almost done.&lt;/p&gt;

&lt;h2&gt;
  
  
  This Dog is a Duck
&lt;/h2&gt;

&lt;p&gt;In some cases, the protocol checks may not be what we want. The obvious reasons coming to mind are:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;We can't really check the desired semantics using the protocol trick.&lt;/li&gt;
&lt;li&gt;We want to wreck havoc.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;For those cases (well, mostly for the first one) the &lt;code&gt;ABC&lt;/code&gt; base class provides another trick. Instead of defining &lt;code&gt;__subclasshook__&lt;/code&gt; to check the interface, we can simple register classes as valid, "virtual subclasses".&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="nn"&gt;abc&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;ABC&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;IDuck&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ABC&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;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;quack&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'Quack!'&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;walk&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'Walk like a duck.'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;IDuck&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;register&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&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;poke&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;duck&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="nb"&gt;isinstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;duck&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;IDuck&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;duck&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;quack&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;duck&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;walk&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Remember that this method puts all the pressure on the programmer. Writing &lt;code&gt;IDuck.register(Dog)&lt;/code&gt; is the equivalent of saying "I vouch for this dog to be a duck". It might pass inspection, but won't necessarily yield the desired results.&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;In this article we covered multiple ways of checking the "duck-ness" of objects. From belonging to the Anas genus, to just placing a sticker on their head saying "Duck!". Some of those methods are more useful or applicable than others, but I still think it worthwhile to be familiar with all of them. Additionally, there are many topics not covered here, like static type checking.&lt;/p&gt;

&lt;h3&gt;
  
  
  Further Reading
&lt;/h3&gt;

&lt;p&gt;The metaclass techniques demonstrated here are simplified versions of code from the &lt;a href="https://docs.python.org/3/library/abc.html"&gt;&lt;code&gt;abc&lt;/code&gt;&lt;/a&gt; and &lt;a href="https://docs.python.org/3/library/typing.html"&gt;&lt;code&gt;typing&lt;/code&gt;&lt;/a&gt; modules. I highly recommend going through those modules and their respective docs, at least at a glance, to extend your knowledge and cover up any holes left by my hand-wavy explanation.&lt;/p&gt;

</description>
      <category>python</category>
      <category>ducktyping</category>
      <category>metaclasses</category>
    </item>
    <item>
      <title>Working Across Time-Zones</title>
      <dc:creator>Tamir Bahar</dc:creator>
      <pubDate>Sat, 09 Jun 2018 16:34:16 +0000</pubDate>
      <link>https://forem.com/tmr232/working-across-time-zones-4843</link>
      <guid>https://forem.com/tmr232/working-across-time-zones-4843</guid>
      <description>&lt;p&gt;Internationalization is a difficult problem is software-engineering. Usually that statement would refer to the technical aspects of providing a good user experience for your customers. Today, however, I am referring to the social aspects.&lt;/p&gt;

&lt;p&gt;Just as it has become common-place to have your users spread across the globe, so it has with developers. It is not uncommon to work with teams in another country, or even to have a specific team-member working from a remote location. Being able to cooperate with developers across the globe is a great enabler. But as the case is with - well - everything, it has some obvious - and some less obvious - pitfalls to avoid.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where (When?) Are My Colleagues?
&lt;/h2&gt;

&lt;p&gt;First and foremost - know the time-zones your colleagues reside in.&lt;/p&gt;

&lt;p&gt;You already know that some of your teammates tend to arrive a bit early or a bit late. You know it, and you adjust to it. You won't make a colleague who starts 2 hours before you stay for a meeting when you know they should be picking up their kids from kindergarten, right?&lt;/p&gt;

&lt;p&gt;Well, all you need to do now is adjust to having teammates arriving at work 10 hours before you.&lt;/p&gt;

&lt;h2&gt;
  
  
  Time For Your 12AM Daily Standup
&lt;/h2&gt;

&lt;p&gt;Yes, that's AM. The one that's confusingly set at midnight.&lt;/p&gt;

&lt;p&gt;Now imagine that you're in a UTC-07:00 time-zone (Pacific Daylight Time) and the rest of your team is in a UTC+03:00 time-zone (Israel Daylight Time). Your daily-standup is at 10AM, which sounds reasonable. But that's in Israel. Sadly, this translates to 12AM for you. But you can accommodate that, can't you?&lt;/p&gt;

&lt;p&gt;Luckily, in the real-world company HQs tend to be in the USA, not Israel. So you're safe. You can hold your meetings at any time &lt;em&gt;you&lt;/em&gt; want, and they'll have to adjust. You can have them wake up early, or stay up late, or just work very awkward shifts. They'll accommodate. But do you really want to make your teammates do that?&lt;/p&gt;

&lt;h2&gt;
  
  
  Get It Done By EOD Today
&lt;/h2&gt;

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

&lt;p&gt;It's not that I don't want to, it simply isn't possible.&lt;/p&gt;

&lt;p&gt;If you have a large enough time-difference (say, 6 hours difference over a 9 hours work-day) your day starts when your colleagues' day ends (or later!)&lt;/p&gt;

&lt;p&gt;No matter how hard they work, they cannot get it done by EOD if EOD has already passed. You can talk about getting things done "by tomorrow", but not EOD. It causes un-needed tension as the need to explain this comes up over and over during planning meetings.&lt;/p&gt;

&lt;h2&gt;
  
  
  Planned Downtime: 9PM-6AM
&lt;/h2&gt;

&lt;p&gt;Great. You've just killed of a day's work for your distant colleagues. 9PM San-Francisco is 7AM in Tel-Aviv. Making it a 7AM-4PM downtime for them.&lt;/p&gt;

&lt;p&gt;I'm not saying you can't do that, but you should try and keep that in mind.&lt;/p&gt;

&lt;h2&gt;
  
  
  And Then, There's Israel
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;And on the seventh day God ended His work which He had done, and He rested on the seventh day from all His work which He had done.&lt;/p&gt;

&lt;p&gt;Then God blessed the seventh day and sanctified it, because in it He rested from all His work which God had created and made.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;em&gt;Genesis 2:2-3&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;And so in Israel we rest on the &lt;em&gt;7th&lt;/em&gt; day, and add the 6th in for good measure.&lt;/p&gt;

&lt;p&gt;We work Sunday through Thursday, and rest on Friday and Saturday. And this is annoying.&lt;/p&gt;

&lt;p&gt;It is annoying when we need support on Sunday and have to wait.&lt;/p&gt;

&lt;p&gt;It is annoying when we travel, and are never sure if we should report Friday as overtime, or Sunday as a day off.&lt;/p&gt;

&lt;p&gt;And it is annoying to be expected to work on Friday evening just because it's a working-day for you. You wouldn't want to work Saturday nights, would you? I didn't think so.&lt;/p&gt;

&lt;p&gt;Also, you should expect email send on Fridays and late Thursdays to be ignored until Sunday.&lt;/p&gt;

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

&lt;p&gt;This has been a bit of a rant, and a bit of advice as well. I'm not sure which dominated the tone.&lt;/p&gt;

&lt;p&gt;This might seem like a minor issue, but it can cause a great deal of pain when ignored.&lt;/p&gt;

&lt;p&gt;But in the end, the rules are simple. All you need to do is be aware, and be considerate. You can do it for the people you physically see everyday, and you can do it for your remote colleagues.&lt;/p&gt;

&lt;p&gt;Try and set your long-distance meeting at times suitable for both ends. And when that isn't possible - make sure you make an effort as well. Waking up an hour earlier every now and then goes a long way.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Adventures in Rust</title>
      <dc:creator>Tamir Bahar</dc:creator>
      <pubDate>Fri, 27 Apr 2018 17:21:57 +0000</pubDate>
      <link>https://forem.com/tmr232/adventures-in-rust-56fc</link>
      <guid>https://forem.com/tmr232/adventures-in-rust-56fc</guid>
      <description>&lt;p&gt;In the few years since Rust came out, I've frequently found myself explaining what an amazing language Rust is. Laying out the ways in which it is going to change the systems-programming world, and what a pleasure Rust is to code in.&lt;/p&gt;

&lt;p&gt;A few months back, I finally got around to trying it out. It was horrid. The darned borrow-checker just wouldn't let me do anything. I couldn't get anything meaningful to compile. Despite years of programming in various languages I felt completely incompetent to handle it. I resolved to drop Rust and focus on other things.&lt;/p&gt;

&lt;p&gt;Despite my initial disappointment and discouragement, I still could not get Rust out of my head. Its premise is too promising to put down after one go. Besides, I cannot be beaten by a programming language! And yet, it can wait. It is too much work for now. Some day, maybe in a few years, I'll write Rust.&lt;/p&gt;

&lt;p&gt;Using Rust, however, is a completely different experience. Rust tools are absolutely amazing. As a Windows user through-and-through I got used to open-source tools (especially command line tools) not being supported on Windows. (No, cygwin is not a valid solution.) I don't blame the devs - they work on Linux. Even if they have the time to spend on the Windows port, they don't necessarily have a Windows machine to test it on. And yet - I am used to being disappointed. That is why, when I first heard of &lt;a href="https://github.com/BurntSushi/ripgrep" rel="noopener noreferrer"&gt;&lt;code&gt;rg&lt;/code&gt;&lt;/a&gt;(an amazing &lt;code&gt;grep&lt;/code&gt; replacement) and &lt;a href="https://github.com/sharkdp/fd" rel="noopener noreferrer"&gt;&lt;code&gt;fd&lt;/code&gt;&lt;/a&gt;(an amazing &lt;code&gt;find&lt;/code&gt; replacement) I &lt;em&gt;knew&lt;/em&gt; that they would not work on Windows. But, being my optimistic self - I checked. And a good thing I did that.&lt;/p&gt;

&lt;p&gt;To install Rust tools, the easiest way is to install the Rust toolset and compile them. A daunting task in every other language, yet a breeze in Rust. &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Head over to &lt;a href="https://rustup.rs/" rel="noopener noreferrer"&gt;rustup.rs&lt;/a&gt; and install Rust
(A single command-line on Linux, a single executable on Windows)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;cargo install ripgrep fd-find&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;That's it. Really. Now use the tools.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This was when I realized how amazing Rust really is. Even if you ignore the language completely - it's tooling and package management is unparalleled. Having published Python packages in the past, I was amazed at the simple publishing and installation mechanisms. Having used C and C++ I was simply amazed at a systems-programming with package management. So while still somewhat scared of the borrow-checker, I decided that my next CLI tool will be written in Rust. The easy-as-pie deployment bought be over completely.&lt;/p&gt;

&lt;p&gt;Some months after that, I finally found myself in need of a new CLI tool. I was faced with a continuous log I wanted to filter for duplicates. &lt;code&gt;sort -u&lt;/code&gt; sorts, so it cannot work on streams. Of course, there is probably some &lt;code&gt;sed&lt;/code&gt; or &lt;code&gt;awk&lt;/code&gt; magic I can use, but I want something simple. Besides, a tool that filters out duplicates seems like the perfect beginner project for getting hands-on with Rust. So I went ahead and creates &lt;a href="https://crates.io/crates/uq" rel="noopener noreferrer"&gt;&lt;code&gt;uq&lt;/code&gt;&lt;/a&gt;. After finishing it, I published it on &lt;a href="https://crates.io/" rel="noopener noreferrer"&gt;crates.io&lt;/a&gt;. &lt;code&gt;cargo install uq&lt;/code&gt; on a second machine, and it worked. Both Windows and Linux. A friend tried it, and it simply worked! I never had such a pleasant deployment experience. It is practically easier to install from source then send a compiled binary! And it works cross-platform out of the box.&lt;/p&gt;

&lt;p&gt;A short while later I wanted to group some log entries by a regex. I looked around and could not find a simple way to do it. So, once again, I turned to Rust. Some borrow-checker-wrestling later and the first version of &lt;a href="https://crates.io/crates/groupby" rel="noopener noreferrer"&gt;&lt;code&gt;groupby&lt;/code&gt;&lt;/a&gt; was complete. Yay!&lt;/p&gt;

&lt;p&gt;A short time later I had one of the best open-source experiences I've ever had. Someone started using &lt;code&gt;groupby&lt;/code&gt;, looked at my terrible code, and posted this issue:&lt;/p&gt;


&lt;div class="ltag_github-liquid-tag"&gt;
  &lt;h1&gt;
    &lt;a href="https://github.com/lostutils/groupby/issues/1" rel="noopener noreferrer"&gt;
      &lt;img class="github-logo" alt="GitHub logo" src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg"&gt;
      &lt;span class="issue-title"&gt;
        Little code suggestions
      &lt;/span&gt;
      &lt;span class="issue-number"&gt;#1&lt;/span&gt;
    &lt;/a&gt;
  &lt;/h1&gt;
  &lt;div class="github-thread"&gt;
    &lt;div class="timeline-comment-header"&gt;
      &lt;a href="https://github.com/vorner" rel="noopener noreferrer"&gt;
        &lt;img class="github-liquid-tag-img" src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Favatars2.githubusercontent.com%2Fu%2F11783500%3Fv%3D4" alt="vorner avatar"&gt;
      &lt;/a&gt;
      &lt;div class="timeline-comment-header-text"&gt;
        &lt;strong&gt;
          &lt;a href="https://github.com/vorner" rel="noopener noreferrer"&gt;vorner&lt;/a&gt;
        &lt;/strong&gt; posted on &lt;a href="https://github.com/lostutils/groupby/issues/1" rel="noopener noreferrer"&gt;&lt;time&gt;Mar 15, 2018&lt;/time&gt;&lt;/a&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;div class="ltag-github-body"&gt;
      &lt;p&gt;Hello&lt;/p&gt;
&lt;p&gt;I find this little program will be useful for many things I do (I usually do something like that with combination of sed, sort, …). I also looked into the code. Do I guess right that you're still learning Rust? Could I provide few little tips?&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;I glimpsed at least one unwrap that can be triggered by the user input (giving a too large group ID), which will result in ugly error message instead of nice useful one.&lt;/li&gt;
&lt;li&gt;Do you choose &lt;code&gt;BTreeMap&lt;/code&gt;/&lt;code&gt;BTreeSet&lt;/code&gt; for some specific reason? Is it the order of elements? If not, &lt;code&gt;HashMap&lt;/code&gt; and &lt;code&gt;HashSet&lt;/code&gt; are likely to be faster.&lt;/li&gt;
&lt;li&gt;Both variants (unique vs all) look very similar and differ only in the inner data type and the method used to &lt;code&gt;push&lt;/code&gt;/&lt;code&gt;insert&lt;/code&gt;. I think this could be done with just one piece of code that is generic over the type, and adding your own trait that implements the adding for either. Would you like me to show you such code?&lt;/li&gt;
&lt;/ul&gt;

    &lt;/div&gt;
    &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/lostutils/groupby/issues/1" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;Having someone more experienced in Rust come in and help me improve my very naïve code was great. And it was my first time getting a "this is great, may I help you?" comment and not a "this is great, I want this as well" one.&lt;/p&gt;

&lt;p&gt;For the time being, I keep spending more time wrestling the borrow-checker than writing actual code in Rust. But I am (almost) sure it is due to lack of experience. On the plus-side, I'm becoming better at detecting lifetime issues in other languages as well.&lt;/p&gt;

&lt;p&gt;So, for anyone who hasn't done it yet, I highly recommend using Rust-based tools. Just for the amazing experience of things working (and compiling!) out of the box. Later, if you choose to actually code in it, be sure to brace yourself for a somewhat bumpy ride. Friends tell me that after a time Rust becomes easier, speeding up their development. I'm not there yet, but I'm working on it.&lt;/p&gt;

</description>
      <category>rust</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Types of Loops</title>
      <dc:creator>Tamir Bahar</dc:creator>
      <pubDate>Sat, 27 Jan 2018 14:00:09 +0000</pubDate>
      <link>https://forem.com/tmr232/types-of-loops-1n55</link>
      <guid>https://forem.com/tmr232/types-of-loops-1n55</guid>
      <description>&lt;p&gt;Recently I've been helping &amp;amp; tutoring some true code beginners. Not someone new to a language, but completely new to programming.&lt;/p&gt;

&lt;p&gt;I've done a lot of training in the past. Both beginner and advanced training, both programming and reverse-engineering. But as green as my previous students have been, they have always had some prior knowledge, some experience with code. In at least one programming language.&lt;/p&gt;

&lt;p&gt;Usually the training is about teaching language features, special tricks, best practices, and getting the trainees familiar with the new patterns. The trainees send out probes, looking for familiar things, and I just fill them in at the right time. They know what they are looking for, or can be easily guided towards the right thing. When people are completely green, they don't. &lt;/p&gt;

&lt;p&gt;This is a very new experience for me, and it got me thinking a lot about programming and the ways we approach code. The patterns we seek to find or form. The amazing number of things that we do without even thinking as experience programmers. Each of those, no matter how simple, needs to be broken up and explained to new-comers. They have no previous knowledge to build upon for this.&lt;/p&gt;

&lt;p&gt;From my current experience, it seems the understanding the meaning of syntax, and understanding forward-flowing programs is easy enough. Conditionals are a non-issue. The first road-block comes with loops. Especially writing loops. Where do I put the return statement? Where do I define my variables?&lt;br&gt;
Trying to explain those things, and give simple rules, I came to some useful realizations of useful patterns, and some painful truths about our use of jargon.&lt;/p&gt;

&lt;p&gt;Let's go ahead and see the patterns.&lt;/p&gt;
&lt;h2&gt;
  
  
  Find Loops
&lt;/h2&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;indexOf&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;haystack&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;needle&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;haystack&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;length&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;needle&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;equals&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;haystack&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;]))&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;In those loops we iterate over the array, looking for an item that fulfills our condition. Once we find it, we immediately return that value. There is no need to declare any variables.&lt;/p&gt;
&lt;h2&gt;
  
  
  Count Loops
&lt;/h2&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;countOf&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;haystack&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;needle&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;count&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;haystack&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;length&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;needle&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;equals&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;haystack&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;]))&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="o"&gt;++;&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;In those loops we iterate over the array, looking for items that fulfill our condition. Whenever we find one, we increment the count. Once we exhaust the iteration, we return the counter. The counter and return statement are outside the loop.&lt;/p&gt;
&lt;h2&gt;
  
  
  Action Loops
&lt;/h2&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;printAll&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;haystack&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;haystack&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;length&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;haystack&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;]);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;In those loops we iterate over the array, and perform an action on each and every item. There are no variables and no return statements.&lt;/p&gt;

&lt;p&gt;Now, those simple loops can do quite a lot, and can be expanded and composed to do more. And I find that they help beginners. But did you spot my error? I used the word "iterate". &lt;/p&gt;
&lt;h2&gt;
  
  
  Vocabulary
&lt;/h2&gt;

&lt;p&gt;While the meaning of "iterate" is clear to existing programmers, and looking at the loops you can easily tell that we are iterating or looping over &lt;code&gt;haystack&lt;/code&gt;, it is not clear for beginners. Moreover, the words themselves sound weird. This is critical, and becomes more pronounced as you try and loop in slightly more advanced ways&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Node&lt;/span&gt; &lt;span class="n"&gt;current&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;myList&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;head&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="n"&gt;current&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="n"&gt;current&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;current&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getNext&lt;/span&gt;&lt;span class="o"&gt;(),&lt;/span&gt; &lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, we are looping (or iterating) over &lt;code&gt;myList&lt;/code&gt;, but we don't change anything about it, or even access it directly. We do change &lt;code&gt;i&lt;/code&gt; (which is no longer our counter) and &lt;code&gt;current&lt;/code&gt; which is a node. This makes the code and language quite dissonant. "We iterate over &lt;code&gt;myList&lt;/code&gt; while maintaining an index" is a true statement, but not an immediate translation from the code. The language forces to go in a very roundabout manner. This is true for many languages. &lt;br&gt;
But now, consider slightly more modern syntax:&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;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;node&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;enumerate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;myList&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="c1"&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 go"&gt;&lt;code&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;node&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="k"&gt;range&lt;/span&gt; &lt;span class="n"&gt;myList&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c"&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 rust"&gt;&lt;code&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;myList&lt;/span&gt;&lt;span class="nf"&gt;.enumerate&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In all of those, the situation is far clearer. We can see that we're looping over &lt;code&gt;myList&lt;/code&gt;, and it is clear that we have both a node and an index.&lt;br&gt;
While this difference might be minor for experienced programmers, it is a world of difference for newcomers.&lt;/p&gt;

&lt;p&gt;Learning to code is not just learning a programming language. Not just learning to think in a specific way. It is learning your own language again. You know English? Well, now you need to learn programming-English. You know Hebrew? Learn programming-Hebrew. We keep changing the meaning of existing words, and expect people to follow and understand them. It is hard. The least we can do is try and minimize the difference between the code we read (programming languages - Java, C, C++, Python, Go, Rust...) and the code we speak (well, I guess English is a programming language as well?).&lt;/p&gt;

</description>
      <category>teaching</category>
      <category>beginners</category>
      <category>experience</category>
    </item>
    <item>
      <title>Write'em Pull Requests</title>
      <dc:creator>Tamir Bahar</dc:creator>
      <pubDate>Sun, 19 Nov 2017 16:16:21 +0000</pubDate>
      <link>https://forem.com/tmr232/writeem-pull-requests-1n5</link>
      <guid>https://forem.com/tmr232/writeem-pull-requests-1n5</guid>
      <description>&lt;p&gt;This micro-post is provided as a service to some of my friends, who find it too difficult and time consuming to submit pull requests.&lt;/p&gt;

&lt;p&gt;In the past, contributing to open-source was sometimes difficult. You had to contact the maintainers, email them patches, and all sorts of nasty things.&lt;br&gt;
Then, circa 2008, GitHub came along. With GitHub you clone the repo locally, make your changes, push to your own fork, and create a PR. Simple enough.&lt;br&gt;
If you wish to avoid the CLI, though, GitHub allows you to go a step further.&lt;/p&gt;

&lt;p&gt;Say you are using my &lt;a href="https://github.com/tmr232/GraphGrabber"&gt;GraphGrabber&lt;/a&gt; plugin for IDA Pro, and find that it fails in IDA 7.0. The Qt layout is different now, and &lt;a href="https://github.com/tmr232/GraphGrabber/blob/master/graphgrabber.py#L51"&gt;line 51&lt;/a&gt; needs to be changed&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;&lt;span class="gh"&gt;diff --git a/graphgrabber.py b/graphgrabber.py                            
index 8c301b7..5d8191c 100644                                             
&lt;/span&gt;&lt;span class="gd"&gt;--- a/graphgrabber.py                                                     
&lt;/span&gt;&lt;span class="gi"&gt;+++ b/graphgrabber.py                                                     
&lt;/span&gt;&lt;span class="p"&gt;@@ -48,7 +48,12 @@&lt;/span&gt; def graph_zoom_fit():                                  


 def grab_graph():                                                        
&lt;span class="gd"&gt;-    widget = sark.qt.get_widget('IDA View-A').children()[0].children()[0]
&lt;/span&gt;&lt;span class="gi"&gt;+    widget = sark.qt.get_widget('IDA View-A').children()[0]              
+    try:                                                                 
+        widget = widget.children()[0]                                    
+    except IndexError:                                                   
+        pass                                                             
+                                                                         
&lt;/span&gt;     width = widget.width()                                               
     height = widget.height()                                             
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;All you have to do now, is click the &lt;code&gt;Fork this project and edit the file&lt;/code&gt; button&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--aJRnGDxY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/qs899y1xlg4oja9tu9xx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--aJRnGDxY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/qs899y1xlg4oja9tu9xx.png" alt="Edit this file" width="331" height="128"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Edit the file in-place&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--UOZ_6_eO--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/4za6au5s504mi0m7q78n.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--UOZ_6_eO--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/4za6au5s504mi0m7q78n.png" alt="edit-in-place" width="517" height="182"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And propose the change&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--mTAX_IDM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/ntpafy7n2zha6gr9lbet.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--mTAX_IDM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/ntpafy7n2zha6gr9lbet.png" alt="propose-change" width="490" height="294"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;That's it. You're Done!&lt;/p&gt;

&lt;p&gt;Now, sure, there are better ways to do this. Details on reproduction of the error would be nice. And when it is not a bugfix, some further discussion and decisions may be required. But this is a start. And once something is started, it is often easier to follow through then without starting it.&lt;/p&gt;

</description>
    </item>
  </channel>
</rss>
