<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Tips on cassiobotaro</title><link>https://cassiobotaro.dev/en/tags/tips/</link><description>Recent content in Tips on cassiobotaro</description><generator>Hugo</generator><language>en</language><lastBuildDate>Sat, 25 Jul 2026 13:06:19 -0300</lastBuildDate><atom:link href="https://cassiobotaro.dev/en/tags/tips/index.xml" rel="self" type="application/rss+xml"/><item><title>The recipes hidden in the itertools documentation</title><link>https://cassiobotaro.dev/en/posts/itertools-recipes/</link><pubDate>Mon, 13 Jul 2026 00:00:00 +0000</pubDate><guid>https://cassiobotaro.dev/en/posts/itertools-recipes/</guid><description>&lt;p&gt;At the end of the &lt;code&gt;itertools&lt;/code&gt; page there is a section called &lt;a href="https://docs.python.org/3/library/itertools.html#itertools-recipes" class="external-link" target="_blank" rel="noopener"&gt;Itertools Recipes&lt;/a&gt;: a collection of useful functions built by combining the module&amp;rsquo;s building blocks. Flattening a list of lists, finding the first element that passes a test, walking a sequence in windows: a lot of what you would write by hand is already solved there. The recipes do not come ready to use in &lt;code&gt;itertools&lt;/code&gt;, the idea is to copy them into your code. We have already used one of them here, &lt;code&gt;consume&lt;/code&gt;, in the article about &lt;a href="https://cassiobotaro.dev/en/posts/consuming-iterables/" &gt;consuming iterables without allocating memory&lt;/a&gt;. I picked three others that are worth knowing.&lt;/p&gt;</description></item><item><title>Invoking modules with python -m</title><link>https://cassiobotaro.dev/en/posts/python-m-module/</link><pubDate>Mon, 06 Jul 2026 00:00:00 +0000</pubDate><guid>https://cassiobotaro.dev/en/posts/python-m-module/</guid><description>&lt;p&gt;Python has the &lt;code&gt;-m&lt;/code&gt; flag, which locates a module and runs it as a script. And the standard library is full of modules that turn into command line utilities ready to use, with nothing to install.&lt;/p&gt;
&lt;p&gt;Serve the current folder over HTTP:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;python -m http.server
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Format (and validate) a JSON:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;echo &lt;span style="color:#e6db74"&gt;&amp;#39;{&amp;#34;name&amp;#34;: &amp;#34;cassio&amp;#34;, &amp;#34;language&amp;#34;: &amp;#34;python&amp;#34;}&amp;#39;&lt;/span&gt; | python -m json.tool
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;See the calendar for the year in your terminal:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;python -m calendar &lt;span style="color:#ae81ff"&gt;2026&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;You have probably already used the flag without noticing, in commands like &lt;code&gt;python -m venv .venv&lt;/code&gt; or &lt;code&gt;python -m pip install&lt;/code&gt;. It is the same mechanism: &lt;code&gt;-m&lt;/code&gt; locates the module on the import path and executes it as the main program, with &lt;code&gt;__name__&lt;/code&gt; set to &lt;code&gt;&amp;quot;__main__&amp;quot;&lt;/code&gt; (when the target is a package, what runs is its &lt;code&gt;__main__.py&lt;/code&gt;).&lt;/p&gt;</description></item><item><title>Fully comparable objects with a single method</title><link>https://cassiobotaro.dev/en/posts/comparable-objects/</link><pubDate>Wed, 01 Jul 2026 00:00:00 +0000</pubDate><guid>https://cassiobotaro.dev/en/posts/comparable-objects/</guid><description>&lt;h2 id="the-problem"&gt;
 The problem
 &lt;a class="heading-link" href="#the-problem"&gt;
 &lt;i class="fa-solid fa-link" aria-hidden="true" title="Link to heading"&gt;&lt;/i&gt;
 &lt;span class="sr-only"&gt;Link to heading&lt;/span&gt;
 &lt;/a&gt;
&lt;/h2&gt;
&lt;p&gt;For an object to respond to &lt;code&gt;&amp;lt;&lt;/code&gt;, &lt;code&gt;&amp;lt;=&lt;/code&gt;, &lt;code&gt;&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;gt;=&lt;/code&gt;, &lt;code&gt;==&lt;/code&gt; and &lt;code&gt;!=&lt;/code&gt;, Python expects you to implement &lt;code&gt;__lt__&lt;/code&gt;, &lt;code&gt;__le__&lt;/code&gt;, &lt;code&gt;__gt__&lt;/code&gt;, &lt;code&gt;__ge__&lt;/code&gt;, &lt;code&gt;__eq__&lt;/code&gt; and &lt;code&gt;__ne__&lt;/code&gt;. That is six nearly identical methods, tedious to write and easy to leave inconsistent (one says &lt;code&gt;a &amp;lt; b&lt;/code&gt; and another disagrees).&lt;/p&gt;
&lt;h2 id="the-tip"&gt;
 The tip
 &lt;a class="heading-link" href="#the-tip"&gt;
 &lt;i class="fa-solid fa-link" aria-hidden="true" title="Link to heading"&gt;&lt;/i&gt;
 &lt;span class="sr-only"&gt;Link to heading&lt;/span&gt;
 &lt;/a&gt;
&lt;/h2&gt;
&lt;p&gt;Two pieces cover everything:&lt;/p&gt;</description></item><item><title>Running a .zip as a Python application</title><link>https://cassiobotaro.dev/en/posts/running-a-zip-with-python/</link><pubDate>Wed, 24 Jun 2026 00:00:00 +0000</pubDate><guid>https://cassiobotaro.dev/en/posts/running-a-zip-with-python/</guid><description>&lt;h2 id="the-problem"&gt;
 The problem
 &lt;a class="heading-link" href="#the-problem"&gt;
 &lt;i class="fa-solid fa-link" aria-hidden="true" title="Link to heading"&gt;&lt;/i&gt;
 &lt;span class="sr-only"&gt;Link to heading&lt;/span&gt;
 &lt;/a&gt;
&lt;/h2&gt;
&lt;p&gt;You have a Python application spread across several files and you want to ship everything as a single file. What if you could package it into a &lt;code&gt;.zip&lt;/code&gt; and run it with &lt;code&gt;python app.zip&lt;/code&gt;?&lt;/p&gt;
&lt;h2 id="the-tip"&gt;
 The tip
 &lt;a class="heading-link" href="#the-tip"&gt;
 &lt;i class="fa-solid fa-link" aria-hidden="true" title="Link to heading"&gt;&lt;/i&gt;
 &lt;span class="sr-only"&gt;Link to heading&lt;/span&gt;
 &lt;/a&gt;
&lt;/h2&gt;
&lt;p&gt;You can, and it is simpler than it looks. Python knows how to execute a &lt;code&gt;.zip&lt;/code&gt; directly, as long as there is a &lt;code&gt;__main__.py&lt;/code&gt; inside it. Let&amp;rsquo;s start from scratch.&lt;/p&gt;</description></item><item><title>Consuming iterables without allocating memory</title><link>https://cassiobotaro.dev/en/posts/consuming-iterables/</link><pubDate>Wed, 17 Jun 2026 00:00:00 +0000</pubDate><guid>https://cassiobotaro.dev/en/posts/consuming-iterables/</guid><description>&lt;h2 id="the-problem"&gt;
 The problem
 &lt;a class="heading-link" href="#the-problem"&gt;
 &lt;i class="fa-solid fa-link" aria-hidden="true" title="Link to heading"&gt;&lt;/i&gt;
 &lt;span class="sr-only"&gt;Link to heading&lt;/span&gt;
 &lt;/a&gt;
&lt;/h2&gt;
&lt;p&gt;When you just want to &amp;ldquo;run&amp;rdquo; a &lt;code&gt;map&lt;/code&gt;/generator pipeline for its side effects (writing each item to a stream, for example), the reflex is a &lt;code&gt;for&lt;/code&gt; or a &lt;code&gt;list(...)&lt;/code&gt;. The &lt;code&gt;list&lt;/code&gt; allocates an entire list that gets thrown away right after, wasting memory for nothing. The &lt;code&gt;for&lt;/code&gt; solves the memory issue, but the loop runs in pure Python.&lt;/p&gt;
&lt;h2 id="the-tip"&gt;
 The tip
 &lt;a class="heading-link" href="#the-tip"&gt;
 &lt;i class="fa-solid fa-link" aria-hidden="true" title="Link to heading"&gt;&lt;/i&gt;
 &lt;span class="sr-only"&gt;Link to heading&lt;/span&gt;
 &lt;/a&gt;
&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;collections.deque&lt;/code&gt; accepts a &lt;code&gt;maxlen&lt;/code&gt; parameter. With &lt;code&gt;maxlen=0&lt;/code&gt;, it pulls each element and discards it immediately, never growing: that is the &lt;code&gt;itertools&lt;/code&gt; &lt;a href="https://docs.python.org/3/library/itertools.html#itertools-recipes" class="external-link" target="_blank" rel="noopener"&gt;&lt;code&gt;consume&lt;/code&gt;&lt;/a&gt; recipe. Instead of materializing a list only to throw it away, you drain the pipeline in constant memory.&lt;/p&gt;</description></item><item><title>The write protocol</title><link>https://cassiobotaro.dev/en/posts/write-protocol/</link><pubDate>Fri, 15 May 2026 00:00:00 +0000</pubDate><guid>https://cassiobotaro.dev/en/posts/write-protocol/</guid><description>&lt;h2 id="the-problem"&gt;
 The problem
 &lt;a class="heading-link" href="#the-problem"&gt;
 &lt;i class="fa-solid fa-link" aria-hidden="true" title="Link to heading"&gt;&lt;/i&gt;
 &lt;span class="sr-only"&gt;Link to heading&lt;/span&gt;
 &lt;/a&gt;
&lt;/h2&gt;
&lt;p&gt;When a function only needs to write to a stream, typing the argument as &lt;a href="https://docs.python.org/3/library/typing.html#typing-io" class="external-link" target="_blank" rel="noopener"&gt;&lt;code&gt;IO[str]&lt;/code&gt;&lt;/a&gt; is overkill, since you are demanding &lt;code&gt;read&lt;/code&gt;, &lt;code&gt;seek&lt;/code&gt;, &lt;code&gt;close&lt;/code&gt; and the rest of the interface, even though you will never use them.&lt;/p&gt;
&lt;h2 id="the-tip"&gt;
 The tip
 &lt;a class="heading-link" href="#the-tip"&gt;
 &lt;i class="fa-solid fa-link" aria-hidden="true" title="Link to heading"&gt;&lt;/i&gt;
 &lt;span class="sr-only"&gt;Link to heading&lt;/span&gt;
 &lt;/a&gt;
&lt;/h2&gt;
&lt;p&gt;Starting with &lt;strong&gt;Python 3.14&lt;/strong&gt;, the &lt;code&gt;io&lt;/code&gt; module exposes the &lt;code&gt;Writer[T]&lt;/code&gt; and &lt;code&gt;Reader[T]&lt;/code&gt; protocols. They describe only the minimum contract (&lt;code&gt;write()&lt;/code&gt; or &lt;code&gt;read()&lt;/code&gt;), so any object that implements just that method already satisfies the type.&lt;/p&gt;</description></item><item><title>The Money Object</title><link>https://cassiobotaro.dev/en/posts/the-money-object/</link><pubDate>Sun, 01 Mar 2026 00:00:00 +0000</pubDate><guid>https://cassiobotaro.dev/en/posts/the-money-object/</guid><description>&lt;p&gt;&lt;img src="https://cassiobotaro.dev/images/dinheiro.png" alt="Money"&gt;&lt;/p&gt;
&lt;h2 id="the-story"&gt;
 The Story
 &lt;a class="heading-link" href="#the-story"&gt;
 &lt;i class="fa-solid fa-link" aria-hidden="true" title="Link to heading"&gt;&lt;/i&gt;
 &lt;span class="sr-only"&gt;Link to heading&lt;/span&gt;
 &lt;/a&gt;
&lt;/h2&gt;
&lt;p&gt;A while ago I took part in the hiring process of a fairly well known purple bank. I did not get in, but I got valuable feedback about the code I wrote. Putting that feedback together with things I learned afterwards, I decided to revisit the challenge and improve the implementation.&lt;/p&gt;
&lt;p&gt;One of the most significant improvements was creating a &lt;code&gt;Money&lt;/code&gt; object, based on the pattern of the same name described by Martin Fowler in &lt;em&gt;Patterns of Enterprise Application Architecture&lt;/em&gt; (PEAA).&lt;/p&gt;</description></item><item><title>The count and index pitfall in NamedTuple</title><link>https://cassiobotaro.dev/en/posts/namedtuple-count-index-mypy/</link><pubDate>Sat, 17 Jan 2026 00:00:00 +0000</pubDate><guid>https://cassiobotaro.dev/en/posts/namedtuple-count-index-mypy/</guid><description>&lt;p&gt;&lt;img src="https://cassiobotaro.dev/images/type-checking.png" alt="Type checking"&gt;&lt;/p&gt;
&lt;h2 id="the-problem"&gt;
 The Problem
 &lt;a class="heading-link" href="#the-problem"&gt;
 &lt;i class="fa-solid fa-link" aria-hidden="true" title="Link to heading"&gt;&lt;/i&gt;
 &lt;span class="sr-only"&gt;Link to heading&lt;/span&gt;
 &lt;/a&gt;
&lt;/h2&gt;
&lt;p&gt;You are using &lt;code&gt;NamedTuple&lt;/code&gt; to create your data classes and decide to add a field called &lt;code&gt;count&lt;/code&gt; or &lt;code&gt;index&lt;/code&gt;. Everything works perfectly at runtime, but when you run mypy or another type checker, you get strange errors. What is going on?&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;
&lt;table style="border-spacing:0;padding:0;margin:0;border:0;"&gt;&lt;tr&gt;&lt;td style="vertical-align:top;padding:0;margin:0;border:0;"&gt;
&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"&gt;1
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"&gt;2
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"&gt;3
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"&gt;4
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"&gt;5
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"&gt;6
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"&gt;7
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"&gt;8
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td style="vertical-align:top;padding:0;margin:0;border:0;;width:100%"&gt;
&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;from&lt;/span&gt; typing &lt;span style="color:#f92672"&gt;import&lt;/span&gt; NamedTuple
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Item&lt;/span&gt;(NamedTuple):
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; name: str
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; count: int &lt;span style="color:#75715e"&gt;# Danger!&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;item &lt;span style="color:#f92672"&gt;=&lt;/span&gt; Item(name&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;apple&amp;#34;&lt;/span&gt;, count&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;5&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;print(item&lt;span style="color:#f92672"&gt;.&lt;/span&gt;count) &lt;span style="color:#75715e"&gt;# Works at runtime&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Running mypy:&lt;/p&gt;</description></item><item><title>Tracking progress with IntFlag</title><link>https://cassiobotaro.dev/en/posts/tracking-progress-with-intflag/</link><pubDate>Tue, 06 Jan 2026 00:00:00 +0000</pubDate><guid>https://cassiobotaro.dev/en/posts/tracking-progress-with-intflag/</guid><description>&lt;p&gt;&lt;img src="https://cassiobotaro.dev/images/tracking.png" alt="Tracking"&gt;&lt;/p&gt;
&lt;h2 id="the-problem"&gt;
 The Problem
 &lt;a class="heading-link" href="#the-problem"&gt;
 &lt;i class="fa-solid fa-link" aria-hidden="true" title="Link to heading"&gt;&lt;/i&gt;
 &lt;span class="sr-only"&gt;Link to heading&lt;/span&gt;
 &lt;/a&gt;
&lt;/h2&gt;
&lt;p&gt;Imagine you are integrating a new product into your system. This product must have complete details and specifications before being published. But that information is added in separate steps, and not necessarily in order. How do you check that every step has been completed?&lt;/p&gt;
&lt;p&gt;A naive solution would be to use a boolean variable for each step:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;ProductTrack&lt;/span&gt;(models&lt;span style="color:#f92672"&gt;.&lt;/span&gt;Model):
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; product &lt;span style="color:#f92672"&gt;=&lt;/span&gt; models&lt;span style="color:#f92672"&gt;.&lt;/span&gt;ForeignKey(Product, on_delete&lt;span style="color:#f92672"&gt;=&lt;/span&gt;models&lt;span style="color:#f92672"&gt;.&lt;/span&gt;CASCADE)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; has_specification &lt;span style="color:#f92672"&gt;=&lt;/span&gt; models&lt;span style="color:#f92672"&gt;.&lt;/span&gt;BooleanField(default&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;False&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; has_detail &lt;span style="color:#f92672"&gt;=&lt;/span&gt; models&lt;span style="color:#f92672"&gt;.&lt;/span&gt;BooleanField(default&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;False&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;def&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;is_complete&lt;/span&gt;(self):
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; self&lt;span style="color:#f92672"&gt;.&lt;/span&gt;has_specification &lt;span style="color:#f92672"&gt;and&lt;/span&gt; self&lt;span style="color:#f92672"&gt;.&lt;/span&gt;has_detail
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;But what if you need to add more steps? Or remove one? Every change means touching the model, running database migrations and adjusting the logic.&lt;/p&gt;</description></item></channel></rss>