<?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: Kristof Bruyninckx</title>
    <description>The latest articles on Forem by Kristof Bruyninckx (@kristofbcoding).</description>
    <link>https://forem.com/kristofbcoding</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%2F305818%2Fe4afcd94-430e-490c-b8a2-71c4aed26252.png</url>
      <title>Forem: Kristof Bruyninckx</title>
      <link>https://forem.com/kristofbcoding</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/kristofbcoding"/>
    <language>en</language>
    <item>
      <title>The enigma of Python Enums</title>
      <dc:creator>Kristof Bruyninckx</dc:creator>
      <pubDate>Wed, 15 Oct 2025 21:05:38 +0000</pubDate>
      <link>https://forem.com/kristofbcoding/the-enigma-of-python-enums-19k0</link>
      <guid>https://forem.com/kristofbcoding/the-enigma-of-python-enums-19k0</guid>
      <description>&lt;p&gt;The basics of Enums are explained pretty well &lt;a href="https://docs.python.org/3/howto/enum.html" rel="noopener noreferrer"&gt;here&lt;/a&gt;. My goal here is to go over some specific pitfalls and provide some insight into how things work under the hood, without diving into the nitty-gritty details of meta-classes.&lt;/p&gt;

&lt;p&gt;Python Enums are not some special language construct, they are made using Python tools available to us, and provided as part of the standard library. In fact, you could create your own Enum if you wanted to. To do that, you'd use metaclasses, which you can also see in the standard library implementation. For now, the takeaway is that Enums don't require any special syntax unlike in some other languages (for example, in c++ you'd use the reserved keyword &lt;code&gt;enum&lt;/code&gt; or &lt;code&gt;enum class&lt;/code&gt;), whereas is python you create them just like a class.&lt;/p&gt;

&lt;h2&gt;
  
  
  How do Enums work
&lt;/h2&gt;

&lt;p&gt;An Enum is meant to be some limited set of values known statically, before running your code. As previously said, there is no special syntax, You make an enum by inheriting from Enum. Taking an example from the how-to page:&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;Weekday&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Enum&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;MONDAY&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
    &lt;span class="n"&gt;TUESDAY&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;
    &lt;span class="n"&gt;WEDNESDAY&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;
    &lt;span class="n"&gt;THURSDAY&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;
    &lt;span class="n"&gt;FRIDAY&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;
    &lt;span class="n"&gt;SATURDAY&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt;
    &lt;span class="n"&gt;SUNDAY&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;7&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Because you inherit from Enum, the way this class is created is significantly altered. As a side note, this is what metaclasses are for, customizing how classes should work, much like how classes describe how objects should work.&lt;/p&gt;

&lt;p&gt;Most importantly, a finite set of objects is created, one for each property defined on the class, It is made impossible &lt;sup id="fnref1"&gt;1&lt;/sup&gt; to ever create any other objects of this class. Where in a regular class, you create an object by calling the class, this gives us a value based lookup for the enum above.&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;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;Weekday&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Weekday&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FRIDAY&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If we access the object by &lt;code&gt;Weekday.FRIDAY&lt;/code&gt; we get the exact same object. Basically, no matter how we try to access it, only one object was ever created and that object is returned. Keeping this in mind, it makes more sense Enums are compared by identity using &lt;code&gt;is&lt;/code&gt;, as opposed to &lt;code&gt;==&lt;/code&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;💡 Compare enums by identity (using &lt;code&gt;is&lt;/code&gt; or &lt;code&gt;is not&lt;/code&gt;).&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Enum values
&lt;/h2&gt;

&lt;p&gt;There aren't a whole lot of enforced restrictions on the value given to an Enum, but it is important to keep a few things in mind. Mutables can be used but have some performance implications as some operations get less efficient, one of which is mentioned &lt;a href="https://docs.python.org/3/library/enum.html#enum.Enum" rel="noopener noreferrer"&gt;in the docs&lt;/a&gt;. In general, the Enum implementation relies on hashability to do certain things efficiently. With unhashable types, it falls back to a less efficient method. For example, A value based lookup such as in the previous section would take &lt;code&gt;O(n)&lt;/code&gt; time, rather than a simple dict lookup. &lt;/p&gt;

&lt;p&gt;With that in mind, and from my own experience of trying to do things that are too complex with Enums, I'd recommend sticking with either simple types (int, str) or frozen dataclasses as the value type for enums. You could use something like a tuple or named tuple as well, but i find frozen dataclasses to almost always be a better alternative (my &lt;a href="https://dev.to/kristofbcoding/data-oriented-python-3m25"&gt;other blog&lt;/a&gt; may provide more insight on this).&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;💡 Keep your enums simple, use builtin immutables like &lt;code&gt;int&lt;/code&gt; or &lt;code&gt;str&lt;/code&gt;, or basic frozen dataclasses. &lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Enum aliases
&lt;/h2&gt;

&lt;p&gt;One interesting thing happens if you assign the same value for different Enums members:&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;Test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Enum&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;FOO&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;
    &lt;span class="n"&gt;BAR&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Rather than making two enum member objects, you'll get a single object and an alias that points to the same object. This can be shown by an identity comparison&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;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Test&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FOO&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="n"&gt;Test&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;BAR&lt;/span&gt;
&lt;span class="bp"&gt;True&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is covered well by the docs, but i'm bringing it up because it's particularly interesting to look at the combination of aliases and mutables. Looking at the following example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Enum&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;FOO&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;
    &lt;span class="n"&gt;BAR&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Since BAR is just an alias for FOO, you get:&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;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Test&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FOO&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="nf"&gt;append&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="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Test&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;BAR&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;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is one more reason to be mindful of using mutables in the context of enums. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;💡 If you want to prevent aliases, use the &lt;a href="https://docs.python.org/3/library/enum.html#enum.unique" rel="noopener noreferrer"&gt;unique&lt;/a&gt; decorator on your enum class.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  A note on IntEnum, StrEnum and more
&lt;/h2&gt;

&lt;p&gt;Enums are not just an alias to a raw value. Especially when using a type checker, they help in making sure you don't compare apples to oranges. This is because an Enum and its value are separate types, if you want the value of an enum, you use &lt;code&gt;WeekDay.FRIDAY.value&lt;/code&gt;, but you have to be explicit. You can't just pass WeekDay.FRIDAY to a function that accepts integers. On the other hand, the standard library also offer an IntEnum and StrEnum, which blur the lines between value type and enum type. Consider the following example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Direction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;IntEnum&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;UP&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
    &lt;span class="n"&gt;DOWN&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;
    &lt;span class="n"&gt;LEFT&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;
    &lt;span class="n"&gt;RIGHT&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Color&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;IntEnum&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;RED&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
    &lt;span class="n"&gt;GREEN&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;
    &lt;span class="n"&gt;BLUE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The problem with using IntEnum and StrEnum is that these inherit from int and str, and as a result, a bunch of operations suddenly become possible. For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Direction&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;UP&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;
&lt;span class="mi"&gt;3&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;direction&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Direction&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DOWN&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;speed&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;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;speed&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;direction&lt;/span&gt; &lt;span class="c1"&gt;# Comparing these doesn't make sense, with a regular Enum a type checker will flag this
&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Color&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RED&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;Direction&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;UP&lt;/span&gt; &lt;span class="c1"&gt;# We should compare by identity using `is` instead, but if we do so by mistake this happily passes
&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Also any function that can take an integer now also accepts every IntEnum passed to it. &lt;/p&gt;

&lt;p&gt;This is not to say that there aren't ever use-cases for these classes, but most of the time there is a clear separation between an Enum and the internal value that happens to represent it. In this case a regular Enum provides better type safety and prevents some forms of misuse. You have to be explicit about when you want to convert to and from the raw value, and that's a good thing. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;💡 Prefer &lt;code&gt;Enum&lt;/code&gt; over &lt;code&gt;IntEnum&lt;/code&gt; and &lt;code&gt;StrEnum&lt;/code&gt;, as it's more explicit and type-safe when using a type checker.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Final remarks
&lt;/h2&gt;

&lt;p&gt;There is so much more to cover on enums. One of my personal favorites  that i haven't mentioned so far is usage of &lt;a href="https://docs.python.org/3/howto/enum.html#using-automatic-values" rel="noopener noreferrer"&gt;auto&lt;/a&gt;, when I really don't care about the value used to represent an Enum. I haven't mentioned it because i did not have any additional insights that aren't covered by the docs. &lt;/p&gt;

&lt;p&gt;All that's left is one final piece of general advice: When it comes to Enums, Keep it Simple!&lt;/p&gt;




&lt;ol&gt;

&lt;li id="fn1"&gt;
&lt;p&gt;That's not entirely true, it has been made impossible through the standard object creation flow, but it is technically still possible, for example through &lt;code&gt;WeekDay._new_member_&lt;/code&gt; or &lt;code&gt;object.__new__&lt;/code&gt;. This breaks in various ways, you might be able to manually fix those, but please just don't. ↩&lt;/p&gt;
&lt;/li&gt;

&lt;/ol&gt;

</description>
      <category>python</category>
      <category>enums</category>
      <category>coding</category>
    </item>
    <item>
      <title>Back to bash: Customization</title>
      <dc:creator>Kristof Bruyninckx</dc:creator>
      <pubDate>Sun, 20 Jul 2025 11:40:00 +0000</pubDate>
      <link>https://forem.com/kristofbcoding/back-to-bash-customization-285c</link>
      <guid>https://forem.com/kristofbcoding/back-to-bash-customization-285c</guid>
      <description>&lt;p&gt;This post explores a number of different ways in which your bash experience can be customized and, even more so, the underlying mechanism. It's good to be aware of this, as tooling will often either modify your bash startup scripts, or ask you to make the changes. &lt;/p&gt;

&lt;h1&gt;
  
  
  Customize your bash experience with... bash!
&lt;/h1&gt;

&lt;p&gt;Generally, you use bash itself to customize your own bash experience, since every shell you start will begin by running bash code from a couple of startup scripts. &lt;/p&gt;

&lt;p&gt;This means that you can customize things like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;define aliases and functions&lt;/li&gt;
&lt;li&gt;Modify shell options through  &lt;a href=""&gt;set&lt;/a&gt; and &lt;a href=""&gt;shopt&lt;/a&gt;. &lt;/li&gt;
&lt;li&gt;Alter environment variables&lt;/li&gt;
&lt;li&gt;...&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Aliases
&lt;/h2&gt;

&lt;p&gt;When invoked these are replaced by the underlying command. For example, i quite often do &lt;code&gt;ls -lrtah&lt;/code&gt; to list all (a) file details (l) sorted by reversed modification time (rt) in a human readable format (h). I could define an alias as such:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;alias &lt;/span&gt;&lt;span class="nv"&gt;lsd&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"ls -lrtah"&lt;/span&gt; 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now i just need to remember &lt;code&gt;lsd&lt;/code&gt;. If i would have a more complex case that required several commands, i could go for a shell function instead. &lt;/p&gt;

&lt;h2&gt;
  
  
  Shell options
&lt;/h2&gt;

&lt;p&gt;As an example, i can set &lt;code&gt;shopt -s globstar&lt;/code&gt; to make &lt;code&gt;ls **/*.txt&lt;/code&gt;  list files within sub directories. &lt;/p&gt;

&lt;h2&gt;
  
  
  Alter environment
&lt;/h2&gt;

&lt;p&gt;A very common operation is to modify PATH so that your executables are searched in new locations.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;PATH&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"/opt/some_dir/:&lt;/span&gt;&lt;span class="nv"&gt;$PATH&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Using export ensures sub processes have access to the variable as well, for example spawning a shell from within a shell will still 'see' the PATH variable.&lt;/p&gt;

&lt;h1&gt;
  
  
  The loading process
&lt;/h1&gt;

&lt;p&gt;Depending on what kind of shell you start, bash attempts to run the following files &lt;sup id="fnref1"&gt;1&lt;/sup&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Interactive login shell: &lt;code&gt;~/.bash_profile&lt;/code&gt;, &lt;code&gt;~/.bash_login&lt;/code&gt; or &lt;code&gt;~/profile&lt;/code&gt;. These are tried in order as specified, the first one that is found is loaded.&lt;/li&gt;
&lt;li&gt;interactive non-login shell: &lt;code&gt;~/.bashrc&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Since i refer to these files a lot, i'll simply call them the profile and bashrc files from now on. &lt;/p&gt;

&lt;p&gt;you will probably only directly use login shells when using &lt;code&gt;ssh&lt;/code&gt; to access a remote machine. On a GUI based OS, the login shell is typically hidden away, but all shells you launch will be subprocesses of the login shell, taking over its execution environment. Those new shells will only load your bashrc file. Herein lies an important factor in choosing which file to modify. Profile scripts are only executed once upon logging in, while bashrc is ran for every interactive shell you spawn. If you add something to your profile script, you'll need to re-login for this to take effect, as opposed to just spawning a new shell when modifying bashrc. There are alternatives to both undesirable options though, as discussed in the next section. &lt;/p&gt;

&lt;p&gt;It's worth noting that on my ubuntu 24.04, the profile script will also run bashrc (you can verify this on your own setup) as such:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$BASH_VERSION&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt;
    &lt;span class="c"&gt;# include .bashrc if it exists&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="nt"&gt;-f&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$HOME&lt;/span&gt;&lt;span class="s2"&gt;/.bashrc"&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt;
        &lt;span class="nb"&gt;.&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$HOME&lt;/span&gt;&lt;span class="s2"&gt;/.bashrc"&lt;/span&gt;
    &lt;span class="k"&gt;fi  
fi&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is not guaranteed though. &lt;/p&gt;

&lt;h1&gt;
  
  
  Tricks to prevent having to start a new shell
&lt;/h1&gt;

&lt;p&gt;As an example, suppose we have just installed &lt;a href="https://github.com/pyenv/pyenv" rel="noopener noreferrer"&gt;pyenv&lt;/a&gt;. The installation process contains &lt;a href="https://github.com/pyenv/pyenv#b-set-up-your-shell-environment-for-pyenv" rel="noopener noreferrer"&gt;instructions&lt;/a&gt; to update both your profile and bashrc files. Suppose you've updated your bashrc file, the changes don't take effect for the current shell you were using for the installation. Having to start a new shell can be a real pain, which can be circumvented in a couple of ways.&lt;/p&gt;

&lt;h2&gt;
  
  
  Spawning a new shell (worse)
&lt;/h2&gt;

&lt;p&gt;You can use &lt;code&gt;bash&lt;/code&gt; inside your current shell to spawn a new shell, but the old shell remains open as shown by printing out the process tree. The new shell gets the old shell as its parent.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;pstree &lt;span class="nt"&gt;-s&lt;/span&gt; &lt;span class="nv"&gt;$$&lt;/span&gt;
systemd───systemd───gnome-terminal-───bash───bash───pstree
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A very annoying problem with this is that you loose your recent shell history because that only gets written once the old shell is closed &lt;sup id="fnref2"&gt;2&lt;/sup&gt;. I've found this to be quite disruptive. &lt;/p&gt;

&lt;h2&gt;
  
  
  Sourcing startup scripts
&lt;/h2&gt;

&lt;p&gt;Manually telling bash to re-execute the startup script (&lt;code&gt;source ~/.bashrc&lt;/code&gt; or &lt;code&gt;source ~/.profile&lt;/code&gt;) does the job. All that's important here is &lt;a href="https://dev.to/kristofbcoding/back-to-bash-inception-running-bash-inside-bash-e7h#sourcing-the-script"&gt;sourcing the script&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Be aware that newly spawned shells will still not see the changes made to profile unless you manually source the profile script each time. This is because they are started from the hidden login shell provided by your OS, which is now out-of-date with your profile script. &lt;/p&gt;

&lt;p&gt;An important caveat related to that out-of-date login shell here is that if you remove something from your profile script, such as an export, it will still be there even if you source your profile script, since the export is still taken over from the existing out-of-date login shell.&lt;/p&gt;

&lt;p&gt;This is a great option, but it's still useful to know about the others and their downsides. &lt;/p&gt;

&lt;h2&gt;
  
  
  Replacing your shell
&lt;/h2&gt;

&lt;p&gt;You can use &lt;code&gt;exec $BASH&lt;/code&gt;, &lt;code&gt;$BASH&lt;/code&gt; being a variable that is automatically set and pointing to your bash executable, usually &lt;code&gt;/bin/bash&lt;/code&gt;. This essentially replaces the current bash process with a newly spawned bash (loading bashrc as usual). You might also loose some things, such as function definitions and variables that were not exported, this is shown in the example below.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ TEST&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"test"&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nv"&gt;$TEST&lt;/span&gt;
&lt;span class="nb"&gt;test&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="nv"&gt;$BASH&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nv"&gt;$TEST&lt;/span&gt;

&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;TEST&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"test"&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nv"&gt;$TEST&lt;/span&gt;
&lt;span class="nb"&gt;test&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="nv"&gt;$BASH&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nv"&gt;$TEST&lt;/span&gt;
&lt;span class="nb"&gt;test&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It depends on what you were doing, but for me this typically isn't a big deal. This behavior makes sense as we are spawning a new shell so only what was explicitly exported is taken over.&lt;/p&gt;

&lt;p&gt;Note that if you want to reload the profile script, you can run &lt;code&gt;exec bash -l&lt;/code&gt;, giving you a login shell, however any other shell you spawn will still be out-of-date, for the same reason as mentioned in the section above. Logins shells will also run &lt;code&gt;~/.bash_logout&lt;/code&gt; upon exiting.&lt;/p&gt;




&lt;ol&gt;

&lt;li id="fn1"&gt;
&lt;p&gt;It should be noted that there are also system-wide variants that apply first, for every user (&lt;code&gt;/etc/profile&lt;/code&gt; and &lt;code&gt;/etc/bash.bashrc&lt;/code&gt;). ↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn2"&gt;
&lt;p&gt;Under the assumption that you did not modify bash to write history immediately, which is possible using &lt;a href="https://www.gnu.org/software/bash/manual/bash.html#index-PROMPT_005fCOMMAND" rel="noopener noreferrer"&gt;PROMPT_COMMAND&lt;/a&gt; ↩&lt;/p&gt;
&lt;/li&gt;

&lt;/ol&gt;

</description>
      <category>bash</category>
      <category>linux</category>
      <category>shell</category>
    </item>
    <item>
      <title>Data oriented python</title>
      <dc:creator>Kristof Bruyninckx</dc:creator>
      <pubDate>Mon, 24 Feb 2025 22:04:47 +0000</pubDate>
      <link>https://forem.com/kristofbcoding/data-oriented-python-3m25</link>
      <guid>https://forem.com/kristofbcoding/data-oriented-python-3m25</guid>
      <description>&lt;p&gt;There is a plethora of options in python to bundle data together. You could use builtin types such as lists, tuples and dicts. You could also create a class, a named tuple or a dataclass, or go even further and use external libraries such as attrs or pydantic. But when to use what, what are the benefits and downsides of each approach? That is the question i hope to tackle in this blog post.&lt;/p&gt;

&lt;h2&gt;
  
  
  Tuples and Lists
&lt;/h2&gt;

&lt;p&gt;The most basic built-in tuples and lists are very easy to use, but also easy to misuse. Imagine you want to represent a 2-dimensional point of natural numbers. You could do this with a tuple.&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;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;p1&lt;/span&gt; &lt;span class="o"&gt;=&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="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p1&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="c1"&gt;# print the x-coordinate
&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;While this works, this has a number of downsides. The knowledge that this a point with x and y coordinates is not explicit. You may be able to decipher this from the context and variable naming, but this makes the code less readable. Especially if you are accessing individual x and y coordinates as this is done by indexing. &lt;/p&gt;

&lt;p&gt;The lack of readability and intent becomes more apparent if we consider other methods that take points as there input.&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;distance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;tuple&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;p2&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;tuple&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;float&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;math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sqrt&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;p2&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="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;p1&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="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="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p2&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="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;p1&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="o"&gt;**&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Of course, we could create a type alias so that it becomes slightly more readable, but that only helps partially.&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="nb"&gt;type&lt;/span&gt; &lt;span class="n"&gt;Point2D&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;tuple&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="c1"&gt;# Note that this syntax is python 3.12+
&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;distance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Point2D&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;p2&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Point2D&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;math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sqrt&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;p2&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="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;p1&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="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="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p2&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="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;p1&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="o"&gt;**&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;also note that, as tuples are immutable, you can't change the values&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;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;p1&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="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;
&lt;span class="nc"&gt;Traceback &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;most&lt;/span&gt; &lt;span class="n"&gt;recent&lt;/span&gt; &lt;span class="n"&gt;call&lt;/span&gt; &lt;span class="n"&gt;last&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
  &lt;span class="n"&gt;File&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;&amp;lt;stdin&amp;gt;&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;module&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nb"&gt;TypeError&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;tuple&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt; &lt;span class="nb"&gt;object&lt;/span&gt; &lt;span class="n"&gt;does&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;support&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt; &lt;span class="n"&gt;assignment&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;One last thing to note is that tuples, like other sequence types such as list, offer equality by content rather than reference out of the box. This is one thing that is rather desirable for the example.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;p1&lt;/span&gt; &lt;span class="o"&gt;=&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="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;p2&lt;/span&gt; &lt;span class="o"&gt;=&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="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;p1&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;p2&lt;/span&gt; 
&lt;span class="bp"&gt;True&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We may represent the point as a list, which would give us mutability but this also gives us access to all kinds of unwanted methods that can be misused to introduce bugs.&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;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;p1&lt;/span&gt; &lt;span class="o"&gt;=&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="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;p1&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="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt; &lt;span class="c1"&gt;# we can update the value now
&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;p1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;# this really does not make sense in the context of a 2d point
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Named tuples
&lt;/h2&gt;

&lt;p&gt;A better option would be to use named tuples.&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;Point2d&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;NamedTuple&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="nb"&gt;int&lt;/span&gt;
    &lt;span class="n"&gt;y&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;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;p1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Point2d&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="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="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If we now look at the previous distance function it looks quite good.&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;distance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Point2D&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;p2&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Point2D&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;math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sqrt&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;p2&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="n"&gt;p1&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="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="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p2&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;p1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;)&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;While this is a good option, named tuples are always immutable. They also, being tuples, support all operations that regular tuples support. For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;p1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Point2d&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="mf"&gt;1.0&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="mf"&gt;2.0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;# Some tuple operations
&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;x&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="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;p1&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;p1&lt;/span&gt; &lt;span class="o"&gt;==&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="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  
&lt;span class="bp"&gt;True&lt;/span&gt; &lt;span class="c1"&gt;# Given that you can compare with any tuple, this allows comparing apples and oranges without complaint, you might accidentally compare with a tuple containing completely different data and unrelated data.
&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;Test&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="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="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nc"&gt;Test&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="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="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)&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="mi"&gt;3&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="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt; &lt;span class="c1"&gt;# Not exactly desirable in our context. 
&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;el&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;tuple&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&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;h2&gt;
  
  
  Regular Classes
&lt;/h2&gt;

&lt;p&gt;So what else can we do? We could make use of a regular class&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Point2D&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="n"&gt;self&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="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; 
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But this is not enough, Aside from this being slightly more code than the named tuple, we'll have to implement some custom dunder methods or we get 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;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;Point2D&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="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="nc"&gt;Point2D&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="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; 
&lt;span class="bp"&gt;False&lt;/span&gt; &lt;span class="c1"&gt;# By default, object equality will by by reference
&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Point2D&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="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;__main__&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Point2D&lt;/span&gt; &lt;span class="nb"&gt;object&lt;/span&gt; &lt;span class="n"&gt;at&lt;/span&gt; &lt;span class="mh"&gt;0x78d45a6dd890&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This makes sense as regular classes are used in many different contexts, the global default should not narrow down its use-cases. However for data oriented classes you would end up having to write a lot of boilerplate (commonly at least &lt;code&gt;__init__&lt;/code&gt;, &lt;code&gt;__eq__&lt;/code&gt; and &lt;code&gt;__repr__&lt;/code&gt;). &lt;/p&gt;

&lt;h2&gt;
  
  
  Dataclasses
&lt;/h2&gt;

&lt;p&gt;In come dataclasses. By using a simple decorator you automatically get implementations for those dunder methods mentioned above.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;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="nd"&gt;@dataclass&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Point2D&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="nb"&gt;int&lt;/span&gt;
    &lt;span class="n"&gt;y&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;p&gt;Now, we automatically get the following:&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;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;Point2D&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="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="nc"&gt;Point2D&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="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="bp"&gt;True&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Point2D&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="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="nc"&gt;Point2D&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="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="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can customize things to your specific needs by providing some arguments to the decorator as below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt; &lt;span class="nd"&gt;@dataclasses.dataclass&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;init&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;repr&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;eq&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;False&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;unsafe_hash&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;False&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;frozen&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;False&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;match_args&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;kw_only&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;False&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;slots&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;False&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;weakref_slot&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;False&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="err"&gt;¶&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So you can really do a lot with a single line of code. Notably you can use frozen=True to make your dataclass immutable. Also note that if you provide both &lt;code&gt;frozen=True&lt;/code&gt; and &lt;code&gt;eq=True&lt;/code&gt;, you automatically get a sensible hash function so that you can use your object in contexts that require it, such as in sets and for dict keys. &lt;/p&gt;

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

&lt;p&gt;By default, i suggest using the option that is the most restrictive in the sense that it should allow exactly what you need, nothing more. Often this is a choice between dataclasses and pydantic, which i will briefly discuss in a bit. I only use NamedTuple if i have a very specific reason to stay compatible with regular tuples (for example if i am refactoring existing code and i want to retain backwards compatibility). This is the safest in terms of preventing misuse. &lt;/p&gt;

&lt;p&gt;Pydantic is great but don't just use it willy-nilly. If you need to do runtime validation on inputs, whether it being loading from files or any place where you deal with user input it tends to be a great fit. As an example, FastApi is a wonderful framework using pydantic for input validation in the context of building web APIs.&lt;/p&gt;

&lt;p&gt;Finally, though i didn't explicitly handle it because i never used it, there is also the the &lt;a href="https://www.attrs.org/en/stable/index.html" rel="noopener noreferrer"&gt;attrs&lt;/a&gt; package. This predates the standard library dataclasses and seems to be a bit more powerful but also more complex. I suggest you have a look it it (as well i probably) if you encounter an use case that you can't handle with dataclasses.&lt;/p&gt;

</description>
      <category>python</category>
      <category>coding</category>
    </item>
    <item>
      <title>Advent of code 2023: 01</title>
      <dc:creator>Kristof Bruyninckx</dc:creator>
      <pubDate>Thu, 28 Mar 2024 00:09:27 +0000</pubDate>
      <link>https://forem.com/kristofbcoding/advent-of-code-01-4ogp</link>
      <guid>https://forem.com/kristofbcoding/advent-of-code-01-4ogp</guid>
      <description>&lt;p&gt;While it's 2024 and the challenge is long past, I've decided to have a look at the 2023 advent of code. The aim of putting this in a blog series, is to document my approach and gain some feedback. I'm not sure how many of these challenges i'll end up tackling, but i suppose now is as good a moment as any to get started with &lt;a href="https://adventofcode.com/2023/day/1"&gt;number one&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Part 1
&lt;/h2&gt;

&lt;p&gt;As a brief summary, the goal is to parse a bunch of text lines and, for each line, construct a number composed from the first and the last digit encountered. Then all line numbers need to be summed to a single value. The example taking from the challenge should make everything clear:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;1abc2&lt;br&gt;
pqr3stu8vwx&lt;br&gt;
a1b2c3d4e5f&lt;br&gt;
treb7uchet&lt;/p&gt;

&lt;p&gt;In this example, the calibration values of these four lines are 12, 38, 15, and 77. Adding these together produces 142. &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Let's start by making a helper that, for a line of text, extracts the number. As a side note, since the challenge doesn't mention input where no number is present in a line, i suppose we don't really need to cover it. I decided to support this though, by having lines without any digits give zero and have no effect on the final sum.&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_line_num&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;int&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;first_number&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Iterable&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;next&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nf"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ch&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;ch&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;ch&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;isdigit&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;first_digit&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;first_number&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;last_digit&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;first_number&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;reversed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;first_digit&lt;/span&gt;&lt;span class="si"&gt;}{&lt;/span&gt;&lt;span class="n"&gt;last_digit&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I've used an inner function to keep things DRY, since the task of finding the first and the last number is pretty much the same. The implementation is a neat little one-liner pattern i like to use once in a while. Using next with a generator expression gives a very compact way to retrieve the first element matching some condition. A key thing to know here is that next throws a &lt;code&gt;StopIteration&lt;/code&gt; exception by default, but can be given an optional default value to return instead (0). &lt;/p&gt;

&lt;p&gt;The only odd thing here is typing wise. Since there is no char type in python, and reversed gives an iterable of strings, the first_number function takes an &lt;code&gt;Iterable[str]&lt;/code&gt; so that both cases are covered. While this works, it is not ideal. You could pass a list of strings to the function, which is not intended and not caught statically by the type checker. &lt;/p&gt;

&lt;p&gt;All that is left is to take some input lines, pass them to the &lt;code&gt;get_line_number&lt;/code&gt; function and sum them.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_number&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lines&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Iterable&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;]):&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;get_line_num&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;line&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;line&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;lines&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Part 2
&lt;/h2&gt;

&lt;p&gt;For the next part, we need to extend our parsing by also supporting spelled out digits. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;two1nine&lt;br&gt;
eightwothree&lt;br&gt;
abcone2threexyz&lt;br&gt;
xtwone3four&lt;br&gt;
4nineeightseven2&lt;br&gt;
zoneight234&lt;br&gt;
7pqrstsixteen&lt;/p&gt;

&lt;p&gt;In this example, the calibration values are 29, 83, 13, 24, 42, 14, and 76. Adding these together produces 281.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;To solve this I extend the previous method by adding some bookkeeping to track how much of each pattern was encountered so far in &lt;code&gt;pattern_seen_chars&lt;/code&gt;. Each number represents the amount of characters currently seen in sequence of a specific pattern. If the full pattern was encountered, the corresponding number is returned.&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;patterns&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;one&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;two&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;three&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;four&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;five&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;six&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;seven&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;eight&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;nine&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_line_num&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;int&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;first_number&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Iterable&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;patterns&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Sequence&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;pattern_seen_chars&lt;/span&gt; &lt;span class="o"&gt;=&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="o"&gt;*&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;patterns&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;ch&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;line&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;ch&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;isdigit&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
                &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ch&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="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;p&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;patterns&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;p&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;pattern_seen_chars&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="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;ch&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p&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="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;pattern_seen_chars&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="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="mi"&gt;1&lt;/span&gt;
                        &lt;span class="n"&gt;pattern_seen_chars&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="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
                    &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                        &lt;span class="n"&gt;pattern_seen_chars&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="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;p&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="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;ch&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;

        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;

    &lt;span class="n"&gt;first_digit&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;first_number&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;patterns&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;last_digit&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;first_number&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;reversed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;p&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="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;patterns&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;first_digit&lt;/span&gt;&lt;span class="si"&gt;}{&lt;/span&gt;&lt;span class="n"&gt;last_digit&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note that i still use the same method of calling the inner helper to get both the first and the last number. Only this time, the patterns also need to be supplied in reverse (&lt;code&gt;[p[::-1] for p in patterns]&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;The rest of the solution, namely summing all line numbers, stays the same.&lt;/p&gt;

&lt;p&gt;That's it for this challenge. Don't hesitate to give some feedback in case you have done it as well!&lt;/p&gt;

</description>
      <category>python</category>
      <category>adventofcode</category>
      <category>programming</category>
    </item>
    <item>
      <title>AI assisted coding: A word of caution</title>
      <dc:creator>Kristof Bruyninckx</dc:creator>
      <pubDate>Tue, 13 Feb 2024 23:11:44 +0000</pubDate>
      <link>https://forem.com/kristofbcoding/ai-assisted-coding-a-word-of-caution-4cdk</link>
      <guid>https://forem.com/kristofbcoding/ai-assisted-coding-a-word-of-caution-4cdk</guid>
      <description>&lt;p&gt;Ever since the since release of ChatGPT, a myriad of AI tools and assistants, such as Github Copilot, have popped up. AI tools can be used to generate code based on prompting or on the fly suggestions in your IDE. There are concerns regarding the data you share while using these, especially when used in a work environment. But there is another big reason why I'm personally not keen to adopt these kind of tools. The risk of sabotaging my own development skills. Hear me out. &lt;/p&gt;

&lt;p&gt;As a developer, you can use all the tools you want provided that they confirm to your company's policies. At least you should be, developer freedom matters. You are however, in the end, solely responsible for the work you deliver. You cannot blame the tools you used if you copied a piece of code, whether from ChatGPT or one of the older go-tos like StackOverflow.&lt;/p&gt;

&lt;h2&gt;
  
  
  Life long learning
&lt;/h2&gt;

&lt;p&gt;Our capabilities are ever changing. We learn new things every day, but knowledge, if not refreshed, also fades and some knowledge simply becomes outdated. This is especially true in the rapidly evolving field of IT. Thus is important to not just deliver the work we need to deliver, but also use that time effectively to build long-lasting knowledge. &lt;/p&gt;

&lt;p&gt;The conclusion from this is that we should try to incorporate principles of effective learning on the job. I've read some interesting material on this in the past, which i wholeheartedly recommend &lt;sup id="fnref1"&gt;1&lt;/sup&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  How not to use ChatGPT
&lt;/h2&gt;

&lt;p&gt;As coders, we use our toolbox of language features, design patterns and so on to solve new problems. Coming up with a solution should require effort, it should require us to dig into our existing knowledge and try to make new connections. This process of trial and error is an effective tool of learning. On the other hand, generating code with ChatGPT, copying it and then trying to understand it skips this process entirely. It requires less effort, but also gives less long-term gains. Over time, i believe this approach would be a detriment to my coding abilities. It is these same coding abilities that we need to analyse the code generated by ChatGPT.&lt;/p&gt;

&lt;h2&gt;
  
  
  Not all is bad
&lt;/h2&gt;

&lt;p&gt;Much like linters, AI generated code reviews may help you to spot mistakes and improvements. The Key thing is these happen after you've made the effort to write the code. Getting feedback after making the effort is very valuable. The process of trial and error requires knowing that you've made a mistake to then learn from it, otherwise it would just be trail and ignorance. While the AI review may contain mistakes, it will help you reflect on your work and consider alternatives. &lt;/p&gt;

&lt;h2&gt;
  
  
  Final thoughts
&lt;/h2&gt;

&lt;p&gt;I'm sure there are many more ways of how not to use or not to use tools like ChatGPT for work other than the two i've just mentioned. The most important question i ask myself is whether it reduces mental effort. Seeing as effort is an important indicator of creating lasting knowledge, this is something i want to avoid.&lt;/p&gt;




&lt;ol&gt;

&lt;li id="fn1"&gt;
&lt;p&gt;Brown, P. C. (2014). Make it stick. Belknap Press. ↩&lt;/p&gt;
&lt;/li&gt;

&lt;/ol&gt;

</description>
      <category>chatgpt</category>
      <category>githubcopilot</category>
      <category>programming</category>
      <category>ai</category>
    </item>
    <item>
      <title>Back to bash: Inception, running bash inside bash</title>
      <dc:creator>Kristof Bruyninckx</dc:creator>
      <pubDate>Fri, 02 Feb 2024 23:07:45 +0000</pubDate>
      <link>https://forem.com/kristofbcoding/back-to-bash-inception-running-bash-inside-bash-e7h</link>
      <guid>https://forem.com/kristofbcoding/back-to-bash-inception-running-bash-inside-bash-e7h</guid>
      <description>&lt;p&gt;This post will be a shorter one that goes into different ways of running bash scripts inside bash (interactive shell or another bash script). While in general it is a fairly simple process, there are some useful things to keep in mind. At first i wasn't sure if it warranted it's own post, but I've been meaning to make my blogs a bit shorter, and I'm happy how it turned out in the end.&lt;/p&gt;

&lt;p&gt;There's essentially two main ways of running another bash script inside bash (spoiler, there is a third way, but i suspect you won't use it as often).&lt;/p&gt;

&lt;h2&gt;
  
  
  Running a script by specifying the path
&lt;/h2&gt;

&lt;p&gt;First things first, any script you try to run directly must have executable permissions. This is not the default when creating files, so you must remember to add them. As an example, granting only the user that owns the file access to execute it can be done using &lt;code&gt;chmod u+x a.bash&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;To run another bash script, simply specify the path, as in &lt;code&gt;./a.bash&lt;/code&gt;, to run it in the current working directory. Note that this is no different from how you would run any other program. Also note that the path to the script/executable must be given, hence the &lt;code&gt;./&lt;/code&gt; prefix. Bash will do a few things under the hood:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Prepare a new execution environment for the command. This contains a couple of things &lt;sup id="fnref1"&gt;1&lt;/sup&gt;, the most important of which are the current working directory and the environment variables. These are inherited from the parent execution environment. &lt;/li&gt;
&lt;li&gt;Run the script into a new bash process with the newly prepared execution environment. Any changes the script makes to its environment do not affect the parent. As an example, consider the following script that sets an environment variable (export)
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;export ABC="42"
cd ../
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When executed, we can observe that the &lt;code&gt;ABC&lt;/code&gt; variable is not available in the environment of the parent, nor is the working directory altered.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;~/some_dir/other_dir$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;./a.bash 
&lt;span class="gp"&gt;~/some_dir/other_dir$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nv"&gt;$ABC&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Sourcing the script
&lt;/h2&gt;

&lt;p&gt;The source builtin, as in &lt;code&gt;source a.bash&lt;/code&gt; or &lt;code&gt;. a.bash&lt;/code&gt; (the first is just an alias for the latter), can be used to execute all commands from a given script in the current execution environment, allowing you to effectively run scripts that alter the environment and the working directory. The example from above is shown again, but this time it affects the shell.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;~/some_dir/other_dir$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;source&lt;/span&gt; ./a.bash 
&lt;span class="gp"&gt;~/some_dir$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nv"&gt;$ABC&lt;/span&gt;
&lt;span class="go"&gt;42

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

&lt;/div&gt;



&lt;h2&gt;
  
  
  Running scripts from PATH
&lt;/h2&gt;

&lt;p&gt;Remember how i said the executable must be specified as a path? That is because, when bash does not see a path (no slashes), it will try to look for an executable in any of the PATH directories. This can be desirable if you want to make a script readily available from any location. For example, if you add the &lt;code&gt;a.bash&lt;/code&gt; file from before to &lt;code&gt;/usr/local/bin&lt;/code&gt;, you can run it, like any other program, using its name, &lt;code&gt;a.bash&lt;/code&gt; (assuming &lt;code&gt;/usr/local/bin&lt;/code&gt; is in the PATH variable).&lt;/p&gt;

&lt;h2&gt;
  
  
  A final remark
&lt;/h2&gt;

&lt;p&gt;At the very top of a file you want to execute, you can specify what is called a shebang &lt;sup id="fnref2"&gt;2&lt;/sup&gt;. This will be picked up in most Unix systems, and indicates what interpreter should be used to run the script.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#!/usr/bin/bash
...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In fact, it is good practice to put this in shared executable scripts as it ensures that bash will be used even if someone tries to run it in a different shell. &lt;/p&gt;

&lt;p&gt;You can also use this to run scripts in other interpreters, such as python, so that you can use &lt;code&gt;some_script.py&lt;/code&gt; rather than &lt;code&gt;python some_script.py&lt;/code&gt;. If you then drop the .py extension, you can obfuscate the fact that it's running python entirely. &lt;/p&gt;




&lt;ol&gt;

&lt;li id="fn1"&gt;
&lt;p&gt;Among others, the execution environment also includes aliases and signal traps. For a full overview, check the bash manual or &lt;code&gt;man bash&lt;/code&gt; help pages. ↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn2"&gt;
&lt;p&gt;Apparently this is a &lt;a href="https://en.wikipedia.org/wiki/Shebang_(Unix)"&gt;contraption of the 2 characters&lt;/a&gt; used, I never would have guessed that though...  ↩&lt;/p&gt;
&lt;/li&gt;

&lt;/ol&gt;

</description>
      <category>bash</category>
      <category>shell</category>
      <category>linux</category>
    </item>
    <item>
      <title>Async behaviour in python web frameworks</title>
      <dc:creator>Kristof Bruyninckx</dc:creator>
      <pubDate>Mon, 26 Jun 2023 00:14:45 +0000</pubDate>
      <link>https://forem.com/kristofbcoding/async-behaviour-in-python-web-frameworks-cak</link>
      <guid>https://forem.com/kristofbcoding/async-behaviour-in-python-web-frameworks-cak</guid>
      <description>&lt;p&gt;When using python web frameworks it's important to understand how they deal with asynchrony, otherwise you will surely run into some massive performance road bumps as your application scales up. In this blog, I explore some of the biggest differences you may need to be aware of for frameworks like Flask, FastApi, Django and many more. In particular, Flask and FastApi are compared by means of small example applications.&lt;/p&gt;

&lt;h1&gt;
  
  
  The basics of concurrency and parallelism in python
&lt;/h1&gt;

&lt;p&gt;CPython, The most common implementation of Python inherently doesn't support running code in parallel. This is prevented by the GIL (global interpreter lock), which allows only one thread to run python code at a time. This is a rather big topic on its own, more information can be found &lt;a href="https://wiki.python.org/moin/GlobalInterpreterLock" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;This is not to say that nothing can run in parallel, some packages like Numpy are mostly written in c, and while running they may release the GIL until they need to call the python C API or update python objects. IO-bound operations that involve system calls will also release the GIL (because in this case, the kernel is responsible for handling the request safely).&lt;/p&gt;

&lt;p&gt;All in all you must keep in mind that, when writing pure python code, a &lt;em&gt;single process&lt;/em&gt; can run your &lt;em&gt;python code&lt;/em&gt; concurrently, but not in parallel. Note the emphasis, as you can create multiple processes to handle requests in parallel. This is done in web servers by spawning multiple worker processes to handle incoming requests. Typically you want to have a stateless application to support this pattern of deployment.&lt;/p&gt;

&lt;h1&gt;
  
  
  WSGI and ASGI
&lt;/h1&gt;

&lt;p&gt;The Web Server Gateway Interface(WSGI) is a standard to decouple the choice of various web frameworks like Flask and Django from the choice of web servers like Gunicorn or Waitress. Without standardization, the best case scenario is shown below at the left, where each framework is compatible with each web server. Of course in reality, there would be missing links and some would be incompatible. On the right the WSGI standard is introduced. Developers of web frameworks will only have to implement this interface to automatically support all web servers and vice-versa.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnx4aq8w59r3h8l2jky8k.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnx4aq8w59r3h8l2jky8k.png" alt="overview web frameworks" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This kind of indirection through standardisation is pretty common to make compatibility between different kinds of software components easier. Some other good examples are the &lt;a href="https://microsoft.github.io/language-server-protocol/" rel="noopener noreferrer"&gt;LSP project&lt;/a&gt; from Microsoft and &lt;a href="https://onnx.ai/" rel="noopener noreferrer"&gt;ONNX&lt;/a&gt; to represent machine learning models. The first provides a standard so that IDEs don't have to re-invent the weel for every programming language. The latter decouples training frameworks from inference frameworks. Going back to WSGI, you can find a pretty extensive rationale for the WSGI standard &lt;a href="https://peps.python.org/pep-3333/" rel="noopener noreferrer"&gt;here&lt;/a&gt; if interested.&lt;/p&gt;

&lt;p&gt;Asynchronous Server Gateway Interface(ASGI) is also a standardisation, focusing on... asynchronous behaviour. One shortcoming of WSGI is that applications must offer a single synchronous callable that takes a HTTP request and returns the response. A worker (typically multiple worker processes are available and each will handle requests) within WSGI will be blocked until the response is there. In ASGI, the worker may be freed up for other requests rather than actively waiting until it can continue. This allows for a higher throughput, especially when the number of IO bound requests is high. The following figure illustrates this key difference. For WSGI request 1 must be finished before the worker can take on request 2.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzgnyj3eblev07bmh1fhm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzgnyj3eblev07bmh1fhm.png" alt="comparison wsgi asgi" width="292" height="147"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Note that in the explanation above, we have left out workers with multiple threads, as supported by many WSGI web servers. We will get back to that later on&lt;/p&gt;

&lt;h1&gt;
  
  
  Async behavior in WSGI frameworks
&lt;/h1&gt;

&lt;p&gt;It may be somewhat confusing but Flask, which is a WSGI framework, also supports using async for request handlers. This works very differently from async request handlers in an ASGI framework! I'll illustrate this by implementing the same example in Flask(WSGI) and FastAPI(ASGI). &lt;/p&gt;

&lt;p&gt;Consider the following web app in Flask. Two routes are offered to retrieve some resources. Let's assume the resources are on a different machine at a different location, and they may take a while to retrieve (simulated with a sleep call).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;flask&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Flask&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;flask&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;jsonify&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;asyncio&lt;/span&gt;

&lt;span class="n"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Flask&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;resource_ids&lt;/span&gt; &lt;span class="o"&gt;=&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="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;


&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;download_resource&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="c1"&gt;# Dummy method to simulate long running IO
&lt;/span&gt;    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;asyncio&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;dummy_result_id_&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; 


&lt;span class="nd"&gt;@app.route&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/resource/&amp;lt;id&amp;gt;&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;retrieve_resource&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;id&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Get all available resources&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;download_resource&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;jsonify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


&lt;span class="nd"&gt;@app.route&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/resources&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;retrieve_resources&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Get a specific resource&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;asyncio&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;TaskGroup&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;tg&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;dl_tasks&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;tg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create_task&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;download_resource&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="nb"&gt;id&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;resource_ids&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="c1"&gt;# All downloads have completed
&lt;/span&gt;    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;jsonify&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="n"&gt;task&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;result&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;task&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;dl_tasks&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 spin this one up using the WSGI web server Gunicorn (Note that the given options are defaults, but are given here to emphasize their value of 1):&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;&lt;code&gt;gunicorn flask_async:app --workers 1 --threads 1&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;Now we will send 3 requests at the same time and measure the total response time&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;time &lt;/span&gt;curl &lt;span class="nt"&gt;--parallel&lt;/span&gt; &lt;span class="nt"&gt;--parallel-immediate&lt;/span&gt; &lt;span class="nt"&gt;--parallel-max&lt;/span&gt; 3 &lt;span class="nt"&gt;-X&lt;/span&gt; GET http://localhost:8000/resource/1 http://localhost:8000/resource/2 http://localhost:8000/resource/3   &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s1"&gt;'accept: application/json'&lt;/span&gt;
&lt;span class="go"&gt;"dummy_result_id_3"
"dummy_result_id_1"
"dummy_result_id_2"

real    0m15,038s
user    0m0,006s
sys     0m0,000s
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notice how the async route didn't really do anything in this case. However, if we use the other route to get all resources in a single request:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;time &lt;/span&gt;curl &lt;span class="nt"&gt;-X&lt;/span&gt; GET http://localhost:8000/resources &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s1"&gt;'accept: application/json'&lt;/span&gt;
&lt;span class="go"&gt;["dummy_result_id_1","dummy_result_id_2","dummy_result_id_3","dummy_result_id_4","dummy_result_id_5"]

real    0m5,014s
user    0m0,005s
sys     0m0,000s
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here we see what we'd like, Multiple requests are handled concurrently. Before explaining this, let's look at the same program in FastAPI, which is an ASGI application,&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;fastapi&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;FastAPI&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;pydantic&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Field&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;asyncio&lt;/span&gt;

&lt;span class="n"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;FastAPI&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;resource_ids&lt;/span&gt; &lt;span class="o"&gt;=&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="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;


&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;download_resource&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="c1"&gt;# Dummy method to simulate long running IO
&lt;/span&gt;    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;asyncio&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;dummy_result_id_&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; 


&lt;span class="nd"&gt;@app.get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/resource/{id}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;retrieve_resource&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;id&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Field&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ge&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="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Get all available resources&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;download_resource&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;id&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;result&lt;/span&gt;


&lt;span class="nd"&gt;@app.get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/resources&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;retrieve_resources&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Get a specific resource&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;asyncio&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;TaskGroup&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;tg&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;dl_tasks&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;tg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create_task&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;download_resource&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="nb"&gt;id&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;resource_ids&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="c1"&gt;# All downloads have completed
&lt;/span&gt;    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;task&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;result&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;task&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;dl_tasks&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To spin this one up, we use an ASGI web server named Uvicorn.&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;&lt;code&gt;uvicorn fastapi_async:app --workers 1&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;For this one, we again run 3 simultaneous requests:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;time &lt;/span&gt;curl &lt;span class="nt"&gt;--parallel&lt;/span&gt; &lt;span class="nt"&gt;--parallel-immediate&lt;/span&gt; &lt;span class="nt"&gt;--parallel-max&lt;/span&gt; 3 &lt;span class="nt"&gt;-X&lt;/span&gt; GET http://localhost:8000/resource/1 http://localhost:8000/resource/2 http://localhost:8000/resource/3   &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s1"&gt;'accept: application/json'&lt;/span&gt;
&lt;span class="go"&gt;"dummy_result_id_3""dummy_result_id_1""dummy_result_id_2"
real    0m5,018s
user    0m0,003s
sys     0m0,003s
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note that, while the route is the same as in Flask (putting aside differences in the frameworks that are irrelevant to async behaviour) the response time here is only 5 seconds, compared to the 15 seconds from before! &lt;/p&gt;

&lt;p&gt;This difference can be explained in where the async event loop is set up. For Flask, being WSGI, it is set up in the request handler itself. This means that if we await a single result in the request handler, control is given back to the event loop, but there is nothing else to do than wait. The requests have to be processed one by one as the only worker is blocked for 5 seconds each time. For the single route that requests all resources, The 3 downloads can be done immediately as they are done within the same request. In contrast, FastAPI, being ASGI, will set up the event loop one level higher. When a request awaits a result, the worker is immediately free to take on a new request.&lt;/p&gt;

&lt;p&gt;Understanding this example is essential when working with different web frameworks, especially if you work on a larger project that mixes WSGI applications (for instance Dash as a frontend, which used Flask) and FastAPI as a backend.&lt;/p&gt;

&lt;h2&gt;
  
  
  A note on threads
&lt;/h2&gt;

&lt;p&gt;Flask can run multiple worker threads, which is the default when running a development server using &lt;code&gt;flask --app flask_async run&lt;/code&gt;. When using threads with Flask there are two backends:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Gthread: Threads in the regular sense, managed and scheduled by the OS. This is expensive and it directly ties the number of concurrent requests you can handle to &lt;code&gt;n_worker_processes * n_threads&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Greenlet: These are pseudo-threads implemented without any OS involvement. The user can decide when control is handed over to a different thread, and/or blocking operations may be altered automatically (using monkeypatch). You could say that with ASGI, async behavior is explicit, while WSGI with greenlets is implicit. Code may look exactly the same as synchronous code, while still gaining async benefits. Performance wise, it is difficult to say which one is better, as both rely on the same backbone of python co-routines. More info can be found &lt;a href="https://greenlet.readthedocs.io/en/stable/" rel="noopener noreferrer"&gt;here&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;It is fair to say there are a lot of possibilities when it comes to running async code in web servers. If you are having issues with responsiveness make sure you know the differences between your development setup and production setup (how many workers and threads are being used, what kind of worker is being used). Also be aware of the underlying standard (WSGI or ASGI) used by your framework when deciding on async routes.&lt;/p&gt;

</description>
      <category>python</category>
      <category>async</category>
      <category>flask</category>
      <category>fastapi</category>
    </item>
    <item>
      <title>Back to bash: [ vs [[, A case of input interpretation</title>
      <dc:creator>Kristof Bruyninckx</dc:creator>
      <pubDate>Tue, 01 Feb 2022 02:06:52 +0000</pubDate>
      <link>https://forem.com/kristofbcoding/back-to-bash-vs-input-interpretation-25om</link>
      <guid>https://forem.com/kristofbcoding/back-to-bash-vs-input-interpretation-25om</guid>
      <description>&lt;p&gt;One can generally get by, by knowing a loose set of rules that bash uses to parse input into commands. There are however some commonplace features that are handled differently, notably aliases and the &lt;code&gt;[[&lt;/code&gt; operator. Understanding these differences can save you quite a bit of &lt;del&gt;googling&lt;/del&gt; stackoverflowing in the long run. It also helps to solidify your understanding of those features themselves. If you catch yourself looking up similar things over and over, it may help to dive a bit deeper in the inner workings of bash. Speaking of diving in, let's!&lt;/p&gt;

&lt;h2&gt;
  
  
  Do I really need to know this?
&lt;/h2&gt;

&lt;p&gt;Before going into some dry rules and definitions, let's make things a bit more concrete. Ask yourself if you really know the difference between &lt;code&gt;[&lt;/code&gt; and &lt;code&gt;[[&lt;/code&gt;. Was it really necessary for bash to add &lt;code&gt;[[&lt;/code&gt; on top of the Bourne shell? Couldn't we get the same behavior there? &lt;/p&gt;

&lt;p&gt;Both of these commands provide the means to do all kinds of conditional tests on files, strings and, in the case of &lt;code&gt;[[&lt;/code&gt; arithmetic comparisons. If a test succeeds, it will return an exit status of 0(success), otherwise 1(error). This means that it can be combined nicely with other features, such as &amp;amp;&amp;amp;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;touch &lt;/span&gt;test.txt
&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="nt"&gt;-f&lt;/span&gt; test.txt &lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"file exists!"&lt;/span&gt;
&lt;span class="go"&gt;file exists!
&lt;/span&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="nt"&gt;-f&lt;/span&gt; test.txt &lt;span class="o"&gt;]]&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"file exists!"&lt;/span&gt;
&lt;span class="go"&gt;file exists!
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Great, but the commands behave exactly the same. Now let's look at some cases where the commands diverge.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;touch &lt;/span&gt;test2.txt
&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="nt"&gt;-f&lt;/span&gt; test.txt &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nt"&gt;-f&lt;/span&gt; test2.txt &lt;span class="o"&gt;]]&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"test"&lt;/span&gt;
&lt;span class="go"&gt;test
&lt;/span&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="nt"&gt;-f&lt;/span&gt; test.txt &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nt"&gt;-f&lt;/span&gt; test2.txt &lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"test"&lt;/span&gt;
&lt;span class="go"&gt;bash: [: missing `]'
&lt;/span&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="nt"&gt;-f&lt;/span&gt; test.txt &lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="nt"&gt;-f&lt;/span&gt; test2.txt &lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"test"&lt;/span&gt;
&lt;span class="go"&gt;test
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;If we want to combine conditional tests with &lt;code&gt;[&lt;/code&gt;, we have to be a bit more verbose. The key difference is that &lt;code&gt;[[&lt;/code&gt; is special to bash, and as such has its own rules of operation. On the other hand &lt;code&gt;[&lt;/code&gt; is a command like any other (with &lt;code&gt;]&lt;/code&gt; as the last argument), and is bound to follow some general rules. In this case &lt;code&gt;[[&lt;/code&gt; overrides the behavior of &lt;code&gt;&amp;amp;&amp;amp;&lt;/code&gt;. Adhering to general rules, the second test fails as it first tries to run &lt;code&gt;[ -f test.txt&lt;/code&gt; and upon succes also &lt;code&gt;-f test2.txt ]&lt;/code&gt;. Note that &lt;code&gt;[&lt;/code&gt; does have it own, less readable syntax to perform an and test &lt;sup id="fnref1"&gt;1&lt;/sup&gt;&lt;/p&gt;

&lt;p&gt;Another important example involves the need for quoting with &lt;code&gt;[&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;PYTHONPATH&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"/some/path"&lt;/span&gt;
&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; &lt;span class="nv"&gt;$PYTHONPATH&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Python path set"&lt;/span&gt;
&lt;span class="go"&gt;Python path set
&lt;/span&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;PYTHONPATH&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"/some/path/with spaces"&lt;/span&gt;
&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; &lt;span class="nv"&gt;$PYTHONPATH&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Python path set"&lt;/span&gt;
&lt;span class="go"&gt;bash: [: /some/path/with: binary operator expected
&lt;/span&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$PYTHONPATH&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Python path set"&lt;/span&gt;
&lt;span class="go"&gt;Python path set
&lt;/span&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; &lt;span class="nv"&gt;$PYTHONPATH&lt;/span&gt; &lt;span class="o"&gt;]]&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Python path set"&lt;/span&gt;
&lt;span class="go"&gt;Python path set
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;With &lt;code&gt;[&lt;/code&gt;, bash will expand &lt;code&gt;$PYTHONPATH&lt;/code&gt;, and split that into multiple parts based on whitespace. Subsequently bash will run &lt;code&gt;[ -n /some/path/with spaces ]&lt;/code&gt;. The command will not know what to do here, as there are too many operands. On the other hand &lt;code&gt;[[&lt;/code&gt; again overrides the default behavior to make things easier and less error-prone. How this happens will be explained in more detail in the next section. Also consider this contradictory example, in which opposite tests both succeed.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; &lt;span class="nv"&gt;$UNDEFINED_VAR&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Test succeeded"&lt;/span&gt;
&lt;span class="go"&gt;Test succeeded
&lt;/span&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="nt"&gt;-z&lt;/span&gt; &lt;span class="nv"&gt;$UNDEFINED_VAR&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Test succeeded"&lt;/span&gt;
&lt;span class="go"&gt;Test succeeded
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;This happens because, as the variable is empty, the command will run as &lt;code&gt;[ -n ]&lt;/code&gt;. If &lt;code&gt;[&lt;/code&gt; receives a single argument (not counting the &lt;code&gt;]&lt;/code&gt;), it will default to checking if the argument is empty or not, which is equivalent to &lt;code&gt;[ -n -n ]&lt;/code&gt;. That last one looks a bit confusing because the string happens to be &lt;code&gt;-n&lt;/code&gt; as well.&lt;/p&gt;

&lt;p&gt;Because of these odd cases, one needs to be careful about quoting, or rather not quoting when using &lt;code&gt;[&lt;/code&gt;.&lt;/p&gt;
&lt;h2&gt;
  
  
  Interpreting rules
&lt;/h2&gt;

&lt;p&gt;To fully explain and understand the differences between &lt;code&gt;[&lt;/code&gt; and &lt;code&gt;[[&lt;/code&gt;, we need to go over some terminology and rules of operation. Bash continuously executes the following steps:&lt;/p&gt;



&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Parse input into words and operators, where quoting rules &lt;br&gt;
can be used to discard the special meaning of characters. More on that here &lt;/p&gt;
&lt;div class="ltag__link"&gt;
  &lt;a href="/kristofbcoding" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__pic"&gt;
      &lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F305818%2Fe4afcd94-430e-490c-b8a2-71c4aed26252.png" alt="kristofbcoding"&gt;
    &lt;/div&gt;
  &lt;/a&gt;
  &lt;a href="/kristofbcoding/back-to-bash-quoting-20bo" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__content"&gt;
      &lt;h2&gt;Back to bash: Quoting&lt;/h2&gt;
      &lt;h3&gt;Kristof Bruyninckx ・ Jan 10 '22&lt;/h3&gt;
      &lt;div class="ltag__link__taglist"&gt;
        &lt;span class="ltag__link__tag"&gt;#bash&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#linux&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#shell&lt;/span&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/a&gt;
&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Word: Any collection of characters treated as a unit by bash&lt;/li&gt;
&lt;li&gt;Operator: 

&lt;ul&gt;
&lt;li&gt;Control Operator: Determine the flow of execution between multiple commands. Some examples are &lt;code&gt;;&lt;/code&gt;, &lt;code&gt;&amp;amp;&lt;/code&gt;, &lt;code&gt;|&lt;/code&gt;, &lt;code&gt;||&lt;/code&gt; and &lt;code&gt;&amp;amp;&amp;amp;&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Redirection Operator: The &lt;code&gt;&amp;gt;&lt;/code&gt; and &lt;code&gt;&amp;lt;&lt;/code&gt; based operators used to redirect stdin, stdout and stderr.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Metacharacter: Any character that causes input to be split into several words. The most common ones are &lt;code&gt;space&lt;/code&gt; and &lt;code&gt;newline&lt;/code&gt;, with &lt;code&gt;tab&lt;/code&gt; also being possible. Characters used in Operators are also metacharacters. &lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;In the following example, the input is split into words &lt;code&gt;echo&lt;/code&gt;, &lt;code&gt;a&lt;/code&gt; and &lt;code&gt;b&lt;/code&gt; followed by operator &lt;code&gt;&amp;gt;&lt;/code&gt; and word &lt;code&gt;c&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;echo &lt;/span&gt;a b&amp;gt;c
&lt;/code&gt;&lt;/pre&gt;



&lt;p&gt;Also note that we don't need spaces when using control operators (throwing readability out of the window)&lt;br&gt;
&lt;/p&gt;

&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;echo &lt;/span&gt;a&amp;amp;&amp;amp;echo b
&lt;span class="go"&gt;a
b
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;




&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;Organize words and operators into a tree of commands. At this point, a distinction is made between &lt;strong&gt;simple commands&lt;/strong&gt;, like &lt;code&gt;[&lt;/code&gt; and &lt;strong&gt;compound commands&lt;/strong&gt;, like &lt;code&gt;[[&lt;/code&gt;. Simple commands follow the upcoming rules strictly, while compound commands may deviate. As a user, we can create simple commands at will, either through creating and executing separate bash scripts, or defining and using bash functions. Contrary to this, we cannot create our own compound commands. &lt;/p&gt;

&lt;p&gt;It is here that operators like &lt;code&gt;&amp;amp;&amp;amp;&lt;/code&gt; from the previous section, but also &lt;code&gt;||&lt;/code&gt; are overridden for &lt;code&gt;[[&lt;/code&gt;. They will cause a split into multiple separate tests, as shown in the previous section.&lt;/p&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;Perform shell expansions. These are some common expansions in order of execution&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Command substitution &lt;code&gt;$()&lt;/code&gt; or &lt;code&gt;` `&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Variable expansion such as &lt;code&gt;$VAR&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Word splitting. Similar to step one, but only split on whitespace. Implicit null arguments (empty string from expanding unset variables) are removed.&lt;/p&gt;

&lt;p&gt;Using &lt;code&gt;[[&lt;/code&gt;, this step is omitted&lt;sup id="fnref2"&gt;2&lt;/sup&gt;, which explains why &lt;code&gt;[[ -n $PYTHONPATH ]] &amp;amp;&amp;amp; echo "Python path"&lt;/code&gt; doesn't need any quotes around &lt;code&gt;$PYTHONPATH&lt;/code&gt;, whether it contains spaces or it is empty. The final command that is ran is equivalent to &lt;code&gt;[[ -n "/some/path/with spaces" ]]&lt;/code&gt; or, when empty, &lt;code&gt;[[ -n "" ]]&lt;/code&gt;. Quotes are not added explicitly, so as to not get something like &lt;code&gt;[[ -n """" ]]&lt;/code&gt; in case &lt;code&gt;$PYTHONPATH&lt;/code&gt; is quoted. This is just the easiest way to show the equivalence. &lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Filename pattern matching, such as in &lt;code&gt;echo *.sh&lt;/code&gt;. This is also not performed for &lt;code&gt;[[&lt;/code&gt;, it would simply use the asterisk directly. &lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;Setup redirections and remove the corresponding symbols from the command. e.g. &lt;code&gt;echo a&amp;gt;b&lt;/code&gt; becomes &lt;code&gt;echo a&lt;/code&gt; and the redirection is set up under the hood.&lt;/p&gt;

&lt;p&gt;Note that since at this point it is already decided whether we are in a simple of compound command, the behavior of redirection symbols can be overridden. In &lt;code&gt;[[&lt;/code&gt; it will perform a lexicographical ordering check like so&lt;br&gt;
&lt;/p&gt;

&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;[[&lt;/span&gt; a &amp;lt; b &lt;span class="o"&gt;]]&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"success!"&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"No success!"&lt;/span&gt;
&lt;span class="go"&gt;success!
&lt;/span&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;[[&lt;/span&gt; b &amp;lt; a &lt;span class="o"&gt;]]&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"success!"&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"No success!"&lt;/span&gt;
&lt;span class="go"&gt;No success!
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;




&lt;/li&gt;

&lt;li&gt;&lt;p&gt;Execute the commands. Actively wait for the  return status of any (sub)command that is executed in the foreground.&lt;/p&gt;&lt;/li&gt;

&lt;/ol&gt;

&lt;p&gt;Given this set of rules, it should now be clear why the following commands are not equivalent, and the first one fails.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; some words &lt;span class="o"&gt;]]&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"words!"&lt;/span&gt;
&lt;span class="go"&gt;bash: syntax error in conditional expression
bash: syntax error near `words'
&lt;/span&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;WORDS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"some words"&lt;/span&gt;
&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; &lt;span class="nv"&gt;$WORDS&lt;/span&gt; &lt;span class="o"&gt;]]&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"words!"&lt;/span&gt;
&lt;span class="go"&gt;words!
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;p&gt;By now, we have an answer to the question we originally started with&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Is it possible to get the behavior from &lt;code&gt;[[&lt;/code&gt; into the Bourne shell?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In the previous section we described the behavior of bash, but the Bourne shell follows the same steps for simple commands. As  discussed in step 2 of the previous section , it is only possible to create simple commands. We have seen some examples where &lt;code&gt;[[&lt;/code&gt; overrides the behavior of simple commands (step 2-4), to make our life easier. So no, doing this in the Bourne shell (in the form of a custom script or function) is not possible.&lt;/p&gt;

&lt;p&gt;Finally we haven't touched upon the &lt;code&gt;=~&lt;/code&gt; operator supported by &lt;code&gt;[[&lt;/code&gt;. This can be used to check if something matches a regular expression and should not be overlooked. As it's not supported by &lt;code&gt;[&lt;/code&gt; and doesn't override any defaults, it didn't really fit in this blog post. It's important enough to at least mention it.   &lt;/p&gt;




&lt;ol&gt;

&lt;li id="fn1"&gt;
&lt;p&gt;&lt;code&gt;[-f test.txt -a -f test2.txt]&lt;/code&gt; ↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn2"&gt;
&lt;p&gt;An exception is made for &lt;code&gt;"$@"&lt;/code&gt; ↩&lt;/p&gt;
&lt;/li&gt;

&lt;/ol&gt;

</description>
      <category>bash</category>
      <category>linux</category>
      <category>shell</category>
    </item>
    <item>
      <title>Back to bash: Quoting</title>
      <dc:creator>Kristof Bruyninckx</dc:creator>
      <pubDate>Mon, 10 Jan 2022 00:27:36 +0000</pubDate>
      <link>https://forem.com/kristofbcoding/back-to-bash-quoting-20bo</link>
      <guid>https://forem.com/kristofbcoding/back-to-bash-quoting-20bo</guid>
      <description>&lt;p&gt;As the default interactive shell on many Linux based systems, bash is used by everyone and their grandmother - which may not be the most apt expression in this case - on a daily basis. I suspect most people, like myself, gradually roll into it while focusing on other tasks. While this gave me a workable knowledge, i think it can still be improved in some areas. &lt;/p&gt;

&lt;p&gt;Back to bash is a series where i revisit bash principles from A to Z, using the official &lt;a href="https://www.gnu.org/software/bash/manual/bash.pdf"&gt;bash manual&lt;/a&gt; as a reference. Each post will focus on one specific element in detail, supported by examples. I will try to include pitfalls as much as possible. &lt;/p&gt;

&lt;p&gt;To start off lightly, let's begin with quoting rules in bash. The purpose of quoting is to remove the meaning of characters that are interpreted in special ways. There are 3 supported ways of quoting, and each have their use-cases. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Scenario: we want to print that a is larger than b.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Backslash
&lt;/h2&gt;

&lt;p&gt;A backslash can be used to quote the subsequent character.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;echo &lt;/span&gt;a&lt;span class="se"&gt;\&amp;gt;&lt;/span&gt;b
&lt;span class="gp"&gt;a&amp;gt;&lt;/span&gt;b
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When not escaped, &lt;code&gt;&amp;gt;&lt;/code&gt; has the special meaning of redirection to files. The following would redirect the command output &lt;code&gt;a&lt;/code&gt; to a file named b, which we print using &lt;code&gt;cat&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;echo &lt;/span&gt;a&amp;gt;b
&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;cat &lt;/span&gt;b
&lt;span class="go"&gt;a
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Single quotes
&lt;/h2&gt;

&lt;p&gt;Single quotes escape all enclosed characters without exception.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s1"&gt;'a&amp;gt;b'&lt;/span&gt;
&lt;span class="gp"&gt;a&amp;gt;&lt;/span&gt;b
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note that single quotes can never be nested, they cannot be escaped within single quotes. Because of this it is generally not great to use in combination with natural language strings.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#Wrong!&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s1"&gt;'Isn\'&lt;/span&gt;t it &lt;span class="nb"&gt;true &lt;/span&gt;that a&amp;gt;b?&lt;span class="s1"&gt;'
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can use the upcoming double quotes or escape single characters with special meaning.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;echo &lt;/span&gt;Isn&lt;span class="se"&gt;\'&lt;/span&gt;t it &lt;span class="nb"&gt;true &lt;/span&gt;that a&lt;span class="se"&gt;\&amp;gt;&lt;/span&gt;b?
&lt;span class="gp"&gt;Isn't it true that a&amp;gt;&lt;/span&gt;b? 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It is ideal for encoding some things like simple json strings, which have double quotes in them, and rarely feature single quotes (even though that is not invalid).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s1"&gt;'{"option_1":42}'&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; config.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Double quotes
&lt;/h2&gt;

&lt;p&gt;Double quotes escape enclosed characters with some notable exceptions for these symbols: &lt;code&gt;$&lt;/code&gt;, &lt;code&gt;`&lt;/code&gt;, &lt;code&gt;\&lt;/code&gt;, and, if history expansion is enabled and the shell is not in POSIX mode, &lt;code&gt;!&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"a&amp;gt;b"&lt;/span&gt;
&lt;span class="gp"&gt;a&amp;gt;&lt;/span&gt;b
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Double quotes can be nested by escaping them.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"He said &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;Isn't a&amp;gt;b?&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="gp"&gt;He said "Isn't a&amp;gt;&lt;/span&gt;b?&lt;span class="s2"&gt;"
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;One notable thing to point out here is the irregular behavior of escaping &lt;code&gt;!&lt;/code&gt;. When escaped, the backslash is maintained! As an example, consider creating a git commit that follows the default formatting guidelines of &lt;a href="https://github.com/vaab/gitchangelog"&gt;gitchangelog&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Attempt 1: Doesn't work, bash will try history expansion and fail.&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;git commit &lt;span class="nt"&gt;-m&lt;/span&gt; &lt;span class="s2"&gt;"fix: dev: Login doesn't set correct access rights !wip"&lt;/span&gt;
&lt;span class="go"&gt;bash: !wip: event not found
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Attempt 2: The commit will now include the backslash!&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;git commit &lt;span class="nt"&gt;-m&lt;/span&gt; &lt;span class="s2"&gt;"fix: dev: Login doesn't set correct access rights &lt;/span&gt;&lt;span class="se"&gt;\!&lt;/span&gt;&lt;span class="s2"&gt;wip"&lt;/span&gt;
&lt;span class="go"&gt;[master (root-commit) f71201c] fix: dev: Login doesn't set correct access rights \!wip
&lt;/span&gt;&lt;span class="c"&gt;...
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Attempt 3: Works but ugly construct&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;git commit &lt;span class="nt"&gt;-m&lt;/span&gt; &lt;span class="s2"&gt;"fix: dev: Login doesn't set correct access rights "&lt;/span&gt;&lt;span class="s1"&gt;'!'&lt;/span&gt;&lt;span class="s2"&gt;"wip"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The bash manual doesn't hint at the reasoning for maintaining the backslash. I'd be curious to know that. Note that, if you don't use it you can also disable history expansion using &lt;code&gt;set +H&lt;/code&gt; in your interactive shell. It is disabled by default in a non-interactive environment (i.e. running scripts).&lt;/p&gt;

&lt;h2&gt;
  
  
  ANSI-C quoting
&lt;/h2&gt;

&lt;p&gt;There is also a special form of quoting &lt;code&gt;$'string'&lt;/code&gt; which will follow escape rules as in ANSI-C, and can be used to interpret things like newlines, tabs and Unicode characters.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s1"&gt;$'a&lt;/span&gt;&lt;span class="se"&gt;\t&lt;/span&gt;&lt;span class="s1"&gt;b'&lt;/span&gt;
&lt;span class="go"&gt;a   b
&lt;/span&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s1"&gt;$'a&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s1"&gt;b'&lt;/span&gt;
&lt;span class="go"&gt;a
b
&lt;/span&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s1"&gt;$'&lt;/span&gt;&lt;span class="se"&gt;\u&lt;/span&gt;&lt;span class="s1"&gt;00AE'&lt;/span&gt;
&lt;span class="go"&gt;®
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note that echo also has its own support for this&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s2"&gt;"a&lt;/span&gt;&lt;span class="se"&gt;\t&lt;/span&gt;&lt;span class="s2"&gt;b"&lt;/span&gt;
&lt;span class="go"&gt;a   b
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Some final thoughts
&lt;/h2&gt;

&lt;p&gt;Quoting is often necessary around variables. Especially when creating scripts that take outside input, we need to be mindful of this. Consider the following script to search for text in a given string. It will take two arguments and print out if the second was found in the first. We will name it &lt;code&gt;search&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/bin/bash&lt;/span&gt;
&lt;span class="nv"&gt;input&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$1&lt;/span&gt;
&lt;span class="nv"&gt;search_str&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$2&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nv"&gt;$input&lt;/span&gt; | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-qi&lt;/span&gt; &lt;span class="nv"&gt;$search_str&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Found a match!"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"No match found!"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If we execute this, it only works with very specific input.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;./search trains i
&lt;span class="go"&gt;Found a match!
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the input contains spaces the script will break&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;./search &lt;span class="s2"&gt;"I like trains"&lt;/span&gt; &lt;span class="s2"&gt;"like trains"&lt;/span&gt;
&lt;span class="go"&gt;grep: trains: No such file or directory
No match found!
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Consider the modified script, which we will name &lt;code&gt;search_v2&lt;/code&gt;. Note that echo doesn't really need the extra quotes as it can work with any number of arguments.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/bin/bash&lt;/span&gt;
&lt;span class="nv"&gt;input&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$1&lt;/span&gt;
&lt;span class="nv"&gt;search_str&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$2&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$input&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-qi&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$search_str&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Found a match!"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"No match found!"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Which will now give the expected output&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;./search_v2 &lt;span class="s2"&gt;"I like trains"&lt;/span&gt; &lt;span class="s2"&gt;"like trains"&lt;/span&gt;
&lt;span class="go"&gt;Found a match!
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's it for quoting. While it is not the most exciting topic, a solid of understanding of the rules can save you a lot of time! &lt;/p&gt;

</description>
      <category>bash</category>
      <category>linux</category>
      <category>shell</category>
    </item>
    <item>
      <title>Neural network initialization: Exploding gradients</title>
      <dc:creator>Kristof Bruyninckx</dc:creator>
      <pubDate>Thu, 28 Jan 2021 01:03:44 +0000</pubDate>
      <link>https://forem.com/kristofbcoding/neural-network-initialization-he-vs-xavier-nkg</link>
      <guid>https://forem.com/kristofbcoding/neural-network-initialization-he-vs-xavier-nkg</guid>
      <description>&lt;p&gt;The goal of this blog post is to delve into the exploding gradients problem for neural networks and its causes. While the subject has extensive exposure through various courses and blog posts on the web, i found it difficult to find sources with the right kind of depth. Throughout this post, things will be explained  by making an explicit link with the neural networks graph structure, something that a lot of people will be familiar with. Finally, there are two questions that will be answered:&lt;br&gt;
1) How exactly are exploding activations linked to exploding gradients?&lt;br&gt;
2) When gradients explode, do they explode equally much throughout the network?&lt;/p&gt;

&lt;p&gt;We will start by covering the background for the exploding/vanishing gradients problem.This builds on a lot of concepts and notations, which we cannot cover in a single post. In such cases, links will be added to relevant material. I also want to give a special mention to one specific &lt;a href="https://www.deeplearning.ai/ai-notes/initialization/" rel="noopener noreferrer"&gt;source&lt;/a&gt;. They have a detailed overview of the everything related to neural network initialization, and most importantly, they offer an amazing embedded visualisation tool.&lt;/p&gt;

&lt;p&gt;A future post will build on this work to explain the specifics of He vs Xavier initialization&lt;/p&gt;

&lt;h2&gt;
  
  
  Neural networks background
&lt;/h2&gt;

&lt;p&gt;Let's use the following not so deep neural network as a leading example: &lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjss5ed6y3lciosndgkz8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjss5ed6y3lciosndgkz8.png" alt="Illustration of backpropagation in a small neural network" width="687" height="189"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;During training, we determine how to slightly nudge our weights, based on a cost function that measures how good of a prediction we made compared to some labeled samples. To determine how much each weight should be nudged, we look at how a tiny change in said weight would impact the cost function. Then we alter the weight in the direction that decreases the cost function for those samples. Applied iteratively, this is a layman's terms explanation for gradient descent. Modern day neural network optimizers, such as Adams, have a bit more whistles and bells, but this covers the absolute basics. More information on the concepts that lead to Adams can be found &lt;a href="https://www.youtube.com/playlist?list=PLkDaE6sCZn6Hn0vK8co82zjQtt3T2Nkqc" rel="noopener noreferrer"&gt;here&lt;/a&gt;&lt;br&gt;
For this blog post, I'll simplify things further by assuming that we update weights for every single sample, which is called stochastic gradient descent. This is not a good idea in practice, as learning will be noisy and slow, but it doesn't really impact this discussion.&lt;/p&gt;

&lt;p&gt;In the figure, the gradient or partial derivative to w00&lt;sup&gt;[2]&lt;/sup&gt; tells us how to update that weight for the next iteration. Nodes and edges that are not greyed out all contribute to the impact of a weight change on the final cost function. In order to calculate this partial derivative, we use the chain rule of derivatives, which breaks it up into a multiplication (note that we use J(x), to represent some cost function) &lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5lzpoepo54e8rko8235k.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5lzpoepo54e8rko8235k.png" alt="backpropagation formula" width="800" height="247"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The last part, which we will call the forward part, can be expanded as: &lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftwox7zp3ar60hzcwhsdk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftwox7zp3ar60hzcwhsdk.png" alt="backpropagation forward expansion" width="800" height="93"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Writing it out explicitly like this shows an important property:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;We can rewrite this as a sum over products, where each term of the product represents a path from an input node through w00&lt;sup&gt;[2]&lt;/sup&gt; up to the output layer. Each term has a number of factors that scales the with the depth of the neural network 2*(L), where L is the amount of layers in the network. The total amount of paths going through w00&lt;sup&gt;[2]&lt;/sup&gt;, is &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Feu624qlaev2iqlhqv6fm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Feu624qlaev2iqlhqv6fm.png" alt="backpropagation number of paths" width="800" height="99"&gt;&lt;/a&gt;&lt;br&gt;
where K is the current layer and ni the amount of nodes in layer i.&lt;/p&gt;

&lt;p&gt;Each path also has a number of terms that scales with the depth of the network. For the forward part, we have one term per layer plus one term for the input. For the backwards part, we have two terms per layer, because we have both the linear computation of the neuron, and the non-linear activation function. Finally, there is also the derivative of the cost function that adds an additional term.&lt;/p&gt;

&lt;h2&gt;
  
  
  Exploding gradients
&lt;/h2&gt;

&lt;p&gt;The sample network has just 5 layers in total. In our sum over products view, that would give &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;2*2*1 paths (the final layer has just one neuron) going through w00&lt;sup&gt;[2]&lt;/sup&gt;
&lt;/li&gt;
&lt;li&gt;individual terms (i.e. paths) consisting of 9 factors (2 for the forward part, 1 for the cost derivative, and 6 from the 3 layers in the backwards path)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If we disregard the activation functions for a moment - Note that the power of the network becomes equivalent to that of linear regression -, we get paths consisting of 6 factors.&lt;/p&gt;

&lt;p&gt;Let's explore the effects of changing some network parameters. Suppose both inputs, as well as each weight is one. Note that the derivative of the cost function to the final activation is the same for each path, we will call it dc.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;If we choose 1 for all weights, the gradient for w00&lt;sup&gt;[2]&lt;/sup&gt; is 4*dc.&lt;/li&gt;
&lt;li&gt;If we decide to change the width of the hidden layers to 100, our calculation becomes 2 * 100 * 1 * dc = 200*dc&lt;/li&gt;
&lt;li&gt;If we change the depth to 100 total layers, our calculation becomes 2**97 * 1 * dc. In this case, changing the depth causes the number of paths, and subsequently the gradient to explode.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The key takeaway is that changing the depth has an exponential effect, both in the amount of paths or terms, as in the amount of factors per term. Depth is directly tied to the importance of a good initialization. &lt;/p&gt;

&lt;p&gt;What if we take the activation functions into the equation? First note the following property&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The partial derivatives to weights in earlier layers are impacted more by activation functions. More precisely, each path has L-K activation factors, where K is the current layer and L the total amount of layers (inlcuding the input layer).&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Let's examine the effect of both ReLu and Sigmoid activations. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2u6ktk4pbpb4yv5iozz5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2u6ktk4pbpb4yv5iozz5.png" alt="ReLu and Sigmoid activations and derivatives" width="800" height="312"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;When using only ReLu activations, they will either do nothing, or drop the contribution of a path if it is negative, thus they will make the partial derivatives for weights in earlier layers higher. &lt;/li&gt;
&lt;li&gt;When using only Sigmoids activations, they will reduce the impact of paths, whether they are positive or negative. The partial derivative will move closer to 0. &lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;Now we have all the elements to answer the initial questions.&lt;br&gt;
1) How exactly are exploding activations linked to exploding gradients?&lt;br&gt;
Activations are part of the gradient formula. The further to the right of the network, the more the gradient correlates with the activation. &lt;br&gt;
2) When gradients explode, do they explode equally much at the back and the front of the network?&lt;br&gt;
As a consequence of the activations, no. The precise effect depends on the used activation functions. If the final layer uses Sigmoid, and all the hidden layers use ReLu (a common setup), both positive and negative paths can be dropped (depending on the sign of the weights in the final layer). &lt;/p&gt;

&lt;p&gt;The next question is, can we initialize weights in a systematic way, so that we can avoid exploding or vanishing gradients? In the next post of this series, we will explore how to do this by using statistics to keep the variance and mean of activations in check, and subsequently - as we have explored in this post - also the gradients. We will see how this results in different initialization methods for each activation function, more precisely, He- and Xavier initialization.&lt;/p&gt;

</description>
      <category>deeplearning</category>
      <category>machinelearning</category>
    </item>
  </channel>
</rss>
