
    
        
        
        
                
        
        
        
                
        
        
        
                
        
        
        
                
        
        
        
                
        
        
        
            
{"version":"https:\/\/jsonfeed.org\/version\/1","title":"mathspp.com feed","home_page_url":"https:\/\/mathspp.com\/blog\/tags\/code-review","feed_url":"https:\/\/mathspp.com\/blog\/tags\/code-review.json","description":"Stay up-to-date with the articles on mathematics and programming that get published to mathspp.com.","author":{"name":"Rodrigo Gir\u00e3o Serr\u00e3o"},"items":[{"title":"mutability and random.shuffle","date_published":"2024-08-27T18:00:00+02:00","id":"https:\/\/mathspp.com\/blog\/mutability-and-random-shuffle","url":"https:\/\/mathspp.com\/blog\/mutability-and-random-shuffle","content_html":"<p>The function <code>random.shuffle<\/code> relies on the mutability of the argument and mutability is a pain in the arse, so we propose an alternative.<\/p>\n\n<p>The function <code>random.shuffle<\/code> shuffles its argument in place, which means it relies on the mutability of the argument.\nThis can introduce bugs if care is not taken.\nConsider the snippet of code that follows:<\/p>\n<pre><code class=\"language-py\">def generate_maze(base_width, base_height):\n    width = 2 * base_width + 1\n    height = 2 * base_height + 1\n    # Initialize the grid with walls\n    maze = [[0 for _ in range(width)] for _ in range(height)]\n\n    DIRECTIONS = [(-1, 0), (1, 0), (0, -1), (0, 1)]\n\n    def carve_passages(x, y):\n        # Mark the current cell as part of the maze.\n        maze[y][x] = 1\n\n        random.shuffle(DIRECTIONS)\n\n        for dx, dy in DIRECTIONS:\n            nx, ny = x + 2 * dx, y + 2 * dy\n            if (\n                0 &lt;= nx &lt; width\n                and 0 &lt;= ny &lt; height\n                and maze[ny][nx] == 0\n            ):\n                # Carve through the wall between the current cell and the neighbor\n                maze[y + dy][x + dx] = 1\n                carve_passages(nx, ny)\n\n    carve_passages(\n        2 * random.randint(0, base_width), 2 * random.randint(0, base_height)\n    )\n\n    return maze<\/code><\/pre>\n<p>The function <code>generate_maze<\/code> uses depth-first search to create a maze like the following, when <code>base_width = 2<\/code> and <code>base_height = 2<\/code>:<\/p>\n<pre><code class=\"language-txt\">1 1 1 0 1\n1 0 0 0 1\n1 1 1 1 1\n1 0 1 0 1\n1 0 1 0 1<\/code><\/pre>\n<p>The path of the maze is represented by the <code>1<\/code>s and the idea of the algorithm is that it will create a fully connected region, connecting all of the cells marked with an <code>x<\/code>:<\/p>\n<pre><code class=\"language-txt\">x . x . x\n. . . . .\nx . x . x\n. . . . .\nx . x . x<\/code><\/pre>\n<p>However, from time to time, the function <code>generate_maze<\/code> generates an incomplete maze, like this:<\/p>\n<pre><code class=\"language-txt\">1 1 1 0 1\n1 0 0 0 1\n1 1 1 1 1\n1 0 0 0 0\n1 0 0 0 0<\/code><\/pre>\n<p>Notice how the bottom-right corner has too many <code>0<\/code>s in a row, and in particular there are two <code>x<\/code>s from the diagram above that were not added to the maze.<\/p>\n<p>After some debugging, I understood the issue: the list <code>DIRECTIONS<\/code> was being shuffled in-place by the call to <code>random.shuffle<\/code> and when I called <code>carve_passages<\/code> recursively, the inner call would reshuffle the list <code>DIRECTIONS<\/code> while the outer call was still traversing the the list <code>DIRECTIONS<\/code>, which would introduce a bug in the loop.<\/p>\n<p>You can fix this by creating a copy of the list every time you want to shuffle it, but a better alternative seems to be to use the function <code>random.sample<\/code> and set the parameter <code>k<\/code> to the size of the list, like this:<\/p>\n<pre><code class=\"language-py\">def generate_maze(base_width, base_height):\n    # ...\n\n    DIRECTIONS = [(-1, 0), (1, 0), (0, -1), (0, 1)]\n\n    def carve_passages(x, y):\n        # Mark the current cell as part of the maze.\n        maze[y][x] = 1\n\n        for dx, dy in random.sample(DIRECTIONS, 4):  #...<\/code><\/pre>","summary":"The function `random.shuffle` relies on the mutability of the argument and mutability is a pain in the arse, so we propose an alternative.","date_modified":"2025-07-23T16:49:02+02:00","tags":["code review","programming","python"],"image":"\/user\/pages\/02.blog\/mutability-and-random-shuffle\/thumbnail.webp"},{"title":"Manipulate Boolean values with conditions","date_published":"2023-11-28T10:00:00+01:00","id":"https:\/\/mathspp.com\/blog\/manipulate-boolean-values-with-conditions","url":"https:\/\/mathspp.com\/blog\/manipulate-boolean-values-with-conditions","content_html":"<p>In this article I explore a common code smell related to conditionals and Boolean values and show how to fix it.<\/p>\n\n<h2 id=\"the-code-smell-with-return\">The code smell with <code>return<\/code><a href=\"#the-code-smell-with-return\" class=\"toc-anchor after\" data-anchor-icon=\"#\" aria-label=\"Anchor\"><\/a><\/h2>\n<p>Consider the function <code>is_even<\/code> shown below.<\/p>\n<pre><code class=\"language-py\">def is_even(number):\n    if number % 2 == 0:\n        return True\n    else:\n        return False\n\nprint(is_even(2))  # True\nprint(is_even(3))  # False<\/code><\/pre>\n<p>What's the code smell it shows?<\/p>\n<p>The code smell is that it uses an <code>if<\/code> statement to manipulate the Boolean value that we will return from the function.\nI'll explain in more detail what I mean, but it'll be easier if I show you the improved version:<\/p>\n<pre><code class=\"language-py\">def is_even(number):\n    return number % 2 == 0\n\nprint(is_even(2))  # True\nprint(is_even(3))  # False<\/code><\/pre>\n<p>Notice how we took the condition from the <code>if<\/code> statement and just plugged it into the <code>return<\/code>, there is no need for an actual <code>if<\/code> statement.<\/p>\n<p>What people sometimes forget is that the condition of the <code>if<\/code> statement is actually an expression:\nit's a piece of code that produces an actual value that you can use.\nSo, whenever you have an <code>if<\/code> statement to pick a Boolean value to return, you can rewrite the return to include the condition(s).<\/p>\n<p>I hope this is making some sense.\nI have another example and an exercise for you, to make sure it is.<\/p>\n<h2 id=\"the-code-smell-with-assignments\">The code smell with assignments<a href=\"#the-code-smell-with-assignments\" class=\"toc-anchor after\" data-anchor-icon=\"#\" aria-label=\"Anchor\"><\/a><\/h2>\n<p>The code smell we're talking about isn't restricted to <code>return<\/code> statements.\nSometimes, the code smell shows itself in assignments like the one below:<\/p>\n<pre><code class=\"language-py\">def morning_routine(rodrigo, day):\n    if day in {\"mon\", \"tue\", \"wed\", \"thu\", \"fri\"}:\n        weekday = True\n        weekend = False\n    else:\n        weekday = False\n        weekend = True\n\n    rodrigo.shower()\n    if weekday:\n        rodrigo.shave()\n    rodrigo.walk_pet()\n    # ...<\/code><\/pre>\n<p>The point here is that we're still using an <code>if<\/code> statement to manipulate Boolean values instead of using the Boolean values directly.\nFor instance, we could assign to <code>weekday<\/code> directly and then set <code>weekend<\/code> to the negation of the value in <code>weekday<\/code>:<\/p>\n<pre><code class=\"language-py\">def morning_routine(rodrigo, day):\n    weekday = day in {\"mon\", \"tue\", \"wed\", \"thu\", \"fri\"}\n    weekend = not weekday\n\n    rodrigo.shower()\n    if weekday:\n        rodrigo.shave()\n    rodrigo.walk_pet()\n    # ...<\/code><\/pre>\n<p>Maybe we don't even need the variable <code>weekend<\/code>!\n(Or maybe we do, it would depend on the remainder of the body of the function <code>morning_routine<\/code>.)<\/p>\n<h2 id=\"exercise\">Exercise<a href=\"#exercise\" class=\"toc-anchor after\" data-anchor-icon=\"#\" aria-label=\"Anchor\"><\/a><\/h2>\n<h3 id=\"function-to-rewrite\">Function to rewrite<a href=\"#function-to-rewrite\" class=\"toc-anchor after\" data-anchor-icon=\"#\" aria-label=\"Anchor\"><\/a><\/h3>\n<p>Consider the function <code>is_ordered_triple<\/code>, shown below:<\/p>\n<pre><code class=\"language-py\">def is_ordered_triple(tup):\n    if len(tup) == 3:\n        if tup[0] &lt;= tup[1] and tup[1] &lt;= tup[2]:\n            return True\n        else:\n            return False\n    else:\n        return False\n\nprint(is_ordered_triple((1, 2)))  # False\nprint(is_ordered_triple((1, 3, 2)))  # False\nprint(is_ordered_triple((1, 2, 3)))  # True<\/code><\/pre>\n<p>Can you rewrite it in the best way possible, and specifically addressing the code smell I discussed above?\nAfter you're done, add your solution to the comments below!<\/p>\n<h3 id=\"solution\">Solution<a href=\"#solution\" class=\"toc-anchor after\" data-anchor-icon=\"#\" aria-label=\"Anchor\"><\/a><\/h3>\n<p>The first thing you can do is rewrite the inner <code>if<\/code> statement so that we return the Boolean value directly:<\/p>\n<pre><code class=\"language-py\">def is_ordered_triple(tup):\n    if len(tup) == 3:\n        return tup[0] &lt;= tup[1] and tup[1] &lt;= tup[2]\n    else:\n        return False\n\nprint(is_ordered_triple((1, 2)))  # False\nprint(is_ordered_triple((1, 3, 2)))  # False\nprint(is_ordered_triple((1, 2, 3)))  # True<\/code><\/pre>\n<p>Then, we can <a href=\"\/blog\/pydonts\/chaining-comparison-operators\">chain comparison operators<\/a> to make...<\/p>","summary":"In this article I explore a common code smell related to conditionals and Boolean values and show how to fix it.","date_modified":"2025-07-23T16:49:02+02:00","tags":["code review","programming","python"],"image":"\/user\/pages\/02.blog\/manipulate-boolean-values-with-conditions\/thumbnail.webp"},{"title":"Why use enums?","date_published":"2023-11-24T12:00:00+01:00","id":"https:\/\/mathspp.com\/blog\/why-use-enums","url":"https:\/\/mathspp.com\/blog\/why-use-enums","content_html":"<p>This article explains why a user would need to use enums in their code and shows how to do it with a simple example.<\/p>\n\n<h2 id=\"what-are-enums-and-why-do-you-need-them\">What are enums and why do you need them?<a href=\"#what-are-enums-and-why-do-you-need-them\" class=\"toc-anchor after\" data-anchor-icon=\"#\" aria-label=\"Anchor\"><\/a><\/h2>\n<p>Let me show you with a clear example.\nConsider the code below.\nThe function <code>greet<\/code> will accept the name of a person and then it will greet them:<\/p>\n<pre><code class=\"language-py\">def greet(user, greeting_type):\n    if greeting_type == \"plain\":\n        return f\"Hello, {user}.\"\n    elif greeting_type == \"warm\":\n        return f\"My dear friend, {user}, how are you doing?\"\n    elif greeting_type == \"casual\":\n        return f\"What's up, {user}?\"\n\nprint(greet(\"Rodrigo\", \"casual\"))\n# \"What's up, Rodrigo?\"<\/code><\/pre>\n<p>The name can be any string, but the greeting type is supposed to be one of three pre-defined values:<\/p>\n<ol><li><code>plain<\/code><\/li>\n<li><code>warm<\/code><\/li>\n<li><code>casual<\/code><\/li>\n<\/ol><p>These three values represent <em>options<\/em>.\nThe user is supposed to supply one of those, otherwise the function won't know what to do (it should probably raise an error, or something of the sort).<\/p>\n<p>Now, imagine this scenario: I'm using the code and I call the function like this <code>greet(\"Rodrigo\", \"PLAIN\")<\/code>.\nWhat happens?<\/p>\n<p>What happens is that the code doesn't work! &#129313;\nI messed up the casing, which should've been lowercase.<\/p>\n<p>Or I could write a typo when writing the option name, like I do so often: <code>greet(\"Rodrigo\", \"WARN\")<\/code>.\nThis would also not work.<\/p>\n<p>Or I could just forget which options are available, which also happens frequently to me when working on projects with more than 3 functions!<\/p>\n<p>Another thing that could also happen is me mixing up the names of the options when writing another function that should accept the same values.\nFor example, I could create a function <code>say_goodbye<\/code> and then, by mistake, expect these three different options:<\/p>\n<ol><li><code>plain<\/code><\/li>\n<li><code>friendly<\/code> (instead of <code>warm<\/code>)<\/li>\n<li><code>casual<\/code><\/li>\n<\/ol><p>If I do this, I end up with two functions that should accept the same greeting types, but don't!<\/p>\n<p>Enums (short for enumerations) are useful to prevent all these mistakes.<\/p>\n<h2 id=\"using-an-enumeration-for-options\">Using an enumeration for options<a href=\"#using-an-enumeration-for-options\" class=\"toc-anchor after\" data-anchor-icon=\"#\" aria-label=\"Anchor\"><\/a><\/h2>\n<p>Here's the same code, but using an <code>Enum<\/code> from the module <code>enum<\/code>, instead of harcoded strings:<\/p>\n<pre><code class=\"language-py\">from enum import auto, Enum\n\nclass GreetingType(Enum):\n    PLAIN = auto()\n    WARM = auto()\n    CASUAL = auto()\n\ndef greet(user, greeting_type):\n    if greeting_type is GreetingType.PLAIN:\n        return f\"Hello, {user}.\"\n    elif greeting_type is GreetingType.WARM:\n        return f\"My dear friend, {user}, how are you doing?\"\n    elif greeting_type is GreetingType.CASUAL:\n        return f\"What's up, {user}?\"\n\nprint(greet(\"Rodrigo\", GreetingType.WARM))\n# 'My dear friend, Rodrigo, how are you doing?'<\/code><\/pre>\n<p>The class <code>Enum<\/code> is what you inherit from, when creating an enumeration, and the function <code>auto<\/code> is an auxiliary function that you can use to populate the values automatically.\nWhat you really care about is the names <code>GreetingType.PLAIN<\/code>, <code>WARM<\/code>, and <code>CASUAL<\/code>, not the actual value that's stored inside, so <code>auto<\/code> will make sure that you get a unique value for each name without having to worry about it.<\/p>\n<p>So, why is this alternative better?<\/p>\n<p>All of the previous problems are easily solved!\nMy IDE will auto-complete the greeting type, so there will be no problems with lowercase vs...<\/p>","summary":"This article explains why a user would need to use enums in their code and shows how to do it with a simple example.","date_modified":"2025-07-23T16:49:02+02:00","tags":["code review","programming","python"],"image":"\/user\/pages\/02.blog\/why-use-enums\/thumbnail.webp"},{"title":"5 ways to flatten a list of lists","date_published":"2023-11-23T11:00:00+01:00","id":"https:\/\/mathspp.com\/blog\/5-ways-to-flatten-a-list-of-lists","url":"https:\/\/mathspp.com\/blog\/5-ways-to-flatten-a-list-of-lists","content_html":"<p>This article shows 5 ways of flattening a list of lists, ranked from worst to best.<\/p>\n\n<h1 id=\"5-ways-to-flatten-a-list-of-lists\">5 ways to flatten a list of lists<a href=\"#5-ways-to-flatten-a-list-of-lists\" class=\"toc-anchor after\" data-anchor-icon=\"#\" aria-label=\"Anchor\"><\/a><\/h1>\n<p>This short article will show 5 ways of flattening a list of lists, ranked from worst to best.<\/p>\n<p>This is the list we'll be using:<\/p>\n<pre><code class=\"language-py\">list_of_lists = [\n    [1, 2, 3],\n    [4, 5],\n    [6],\n    [7, 8, 9],\n]<\/code><\/pre>\n<p>Let's start.<\/p>\n<h2 id=\"5th-using-functools-reduce\">5th &ndash; using <code>functools.reduce<\/code><a href=\"#5th-using-functools-reduce\" class=\"toc-anchor after\" data-anchor-icon=\"#\" aria-label=\"Anchor\"><\/a><\/h2>\n<pre><code class=\"language-pycon\">&gt;&gt;&gt; from functools import reduce\n&gt;&gt;&gt; from operator import add\n&gt;&gt;&gt; flat_list = reduce(add, list_of_lists, [])\n&gt;&gt;&gt; flat_list\n[1, 2, 3, 4, 5, 6, 7, 8, 9]<\/code><\/pre>\n<p>This is not a great idea because using <code>reduce(add, ...)<\/code> is almost always worse than using the equivalent built-in <code>sum<\/code>.<\/p>\n<p>In other words, <code>sum<\/code> is the specialised version of <code>reduce<\/code> that adds things, so you'll almost never need <code>reduce(add, ...)<\/code>.<\/p>\n<p>(<code>reduce<\/code> isn't useless, though. You can and should <a href=\"\/blog\/pydonts\/the-power-of-reduce\">read about <code>reduce<\/code> and its use-cases<\/a>.)<\/p>\n<p>So, this leads clearly to the next version.<\/p>\n<h2 id=\"4th-using-sum\">4th &ndash; using <code>sum<\/code><a href=\"#4th-using-sum\" class=\"toc-anchor after\" data-anchor-icon=\"#\" aria-label=\"Anchor\"><\/a><\/h2>\n<pre><code class=\"language-pycon\">&gt;&gt;&gt; flat_list = sum(list_of_lists, [])\n&gt;&gt;&gt; flat_list\n[1, 2, 3, 4, 5, 6, 7, 8, 9]<\/code><\/pre>\n<p>This is better than option 5.<\/p>\n<p>But it's still not great.<\/p>\n<p>The main reason this isn't great is because <code>sum<\/code> will do too much work.\n(Can you see why?)<\/p>\n<p>Every time we add two lists (the accumulated one and one from <code>list_of_lists<\/code>), we need to create a third list with all of the elements of the two, so we'll waste a lot of time recomputing lists.<\/p>\n<p>So, using <code>sum<\/code> is a neat party trick, and it shows you understand the underlying way in which <code>sum<\/code> works, but it isn't practical.<\/p>\n<h2 id=\"3rd-two-nested-loops\">3rd &ndash; two nested loops<a href=\"#3rd-two-nested-loops\" class=\"toc-anchor after\" data-anchor-icon=\"#\" aria-label=\"Anchor\"><\/a><\/h2>\n<p>This is the KISS solution.\nIt's pretty straightforward and it's a great solution!\nTwo <code>for<\/code> loops and an <code>append<\/code>:<\/p>\n<pre><code class=\"language-py\">&gt;&gt;&gt; flat_list = []\n&gt;&gt;&gt; for sublist in list_of_lists:\n...     for element in sublist:\n...         flat_list.append(element)\n...\n&gt;&gt;&gt; flat_list\n[1, 2, 3, 4, 5, 6, 7, 8, 9]<\/code><\/pre>\n<p>This is a brilliant solution!\nThe reason it's placed in 3rd is not because it's bad, but because you can do even better!<\/p>\n<h2 id=\"2nd-using-a-list-comprehension\">2nd &ndash; using a list comprehension<a href=\"#2nd-using-a-list-comprehension\" class=\"toc-anchor after\" data-anchor-icon=\"#\" aria-label=\"Anchor\"><\/a><\/h2>\n<pre><code class=\"language-pycon\">&gt;&gt;&gt; flat_list = [\n...     element\n...     for sublist in list_of_lists\n...     for element in sublist\n... ]\n&gt;&gt;&gt; flat_list\n[1, 2, 3, 4, 5, 6, 7, 8, 9]<\/code><\/pre>\n<p>This solution is better than the two loops because there are many advantages to using list comprehensions when you have simple <code>for<\/code> loops whose only job is to append items to a new list.<\/p>\n<p>I've written extensively about list comprehensions before!\nIf you're interested (and you should be!) you can <a href=\"\/blog\/pydonts\/list-comprehensions-101\">learn more about list comprehensions and their advantages<\/a>.<\/p>\n<p>The list comprehension is always better than the two loops.\nSo, that's why it comes after the two loops.\nBut the next solution is only better than the list comprehension in some cases.<\/p>\n<h2 id=\"1st-using-itertools-chain\">1st &ndash; using <code>itertools.chain<\/code>:<a href=\"#1st-using-itertools-chain\" class=\"toc-anchor after\" data-anchor-icon=\"#\" aria-label=\"Anchor\"><\/a><\/h2>\n<pre><code class=\"language-pycon\">&gt;&gt;&gt; from itertools import chain\n&gt;&gt;&gt; flat_list = list(chain.from_iterable(list_of_lists))\n&gt;&gt;&gt; flat_list\n[1, 2, 3, 4, 5, 6, 7, 8, 9]...<\/code><\/pre>","summary":"This article shows 5 ways of flattening a list of lists, ranked from worst to best.","date_modified":"2023-11-24T12:26:55+01:00","tags":["code review","programming","python"],"image":"\/user\/pages\/02.blog\/5-ways-to-flatten-a-list-of-lists\/thumbnail.webp"},{"title":"Enumerate from first principles","date_published":"2022-02-22T00:00:00+01:00","id":"https:\/\/mathspp.com\/blog\/enumerate-from-first-principles","url":"https:\/\/mathspp.com\/blog\/enumerate-from-first-principles","content_html":"<p>In this article we reimplement the built-in <code>enumerate<\/code> in the best way possible.<\/p>\n\n<p><img alt=\"&quot;A Python code snippet showing the built-in `enumerate` applied to the string 'rod' and with the optional argument `start`.&quot;\" src=\"\/user\/pages\/02.blog\/enumerate-from-first-principles\/thumbnail.webp\"><\/p>\n<h2 id=\"preamble\">Preamble<a href=\"#preamble\" class=\"toc-anchor after\" data-anchor-icon=\"#\" aria-label=\"Anchor\"><\/a><\/h2>\n<p>In this article, we will use Python to reimplement the built-in <code>enumerate<\/code>.\nWe will start with a rough solution that doesn't really cut it,\nand we will rework it bit by bit until we have a full reimplementation of the built-in <code>enumerate<\/code>.\nWe will use this task as the motivation for studying a series of interesting Python concepts and subtleties.\nAs a by-product of working through this article,\nyou will also gain a better understanding of what the built-in <code>enumerate<\/code> is and how it really works.<\/p>\n<p>After you work through this article, you will:<\/p>\n<ul><li>understand what the built-in <code>enumerate<\/code> is and how it works;<\/li>\n<li>be able to point practical differences between generic iterables and lists;<\/li>\n<li>know what (lazy) generators are;<\/li>\n<li>understand the relationship between <code>zip<\/code> and <code>enumerate<\/code>;<\/li>\n<li>have used the keywords <code>yield<\/code> and <code>yield from<\/code>;<\/li>\n<li>know the difference between <code>yield<\/code> and <code>yield from<\/code>;<\/li>\n<li>be acquainted with infinite generators; and<\/li>\n<li>have a full reimplementation of <code>enumerate<\/code> in Python.<\/li>\n<\/ul><div class=\"notices blue\">\n<p>This article is also the written version of a talk I gave at <a href=\"https:\/\/pycon.lk\/#speakers\" target=\"_blank\" rel=\"nofollow noopener noreferrer\" class=\"external-link no-image\">PyCon Sri Lanka 2022<\/a>.\nThe talk slides are available <a href=\"https:\/\/github.com\/mathspp\/talks\" target=\"_blank\" rel=\"nofollow noopener noreferrer\" class=\"external-link no-image\">here<\/a> and the YouTube recording is <a href=\"https:\/\/youtu.be\/Bdunek7Q8Ss?t=90\" target=\"_blank\" rel=\"nofollow noopener noreferrer\" class=\"external-link no-image\">here<\/a>.<\/p>\n<\/div>\n<h2 id=\"introduction\">Introduction<a href=\"#introduction\" class=\"toc-anchor after\" data-anchor-icon=\"#\" aria-label=\"Anchor\"><\/a><\/h2>\n<p>Imagine you have a string:<\/p>\n<pre><code class=\"language-py\">s = \"hey\"<\/code><\/pre>\n<p>How would you go about printing each character of that string?\nThe typical beginner loop would look like this:<\/p>\n<pre><code class=\"language-py\">for idx in range(len(s)):\n    print(s[idx])<\/code><\/pre>\n<pre><code>r\no\nd<\/code><\/pre>\n<p>However, beginners soon learn about the power of <em>iterables<\/em>,\nwhich lets them write the previous loop in a more explicit and expressive way:<\/p>\n<pre><code class=\"language-py\">for char in s:\n    print(char)<\/code><\/pre>\n<pre><code>r\no\nd<\/code><\/pre>\n<p>Notice how we get to give a name (<code>char<\/code>) to each element of the string,\ninstead of having to use the integer <code>idx<\/code> to index into the string.\nThis is possible because strings are <em>iterables<\/em>:\nobjects that can be traversed;\nobjects for which we can get their items one by one, in a loop.<\/p>\n<p>Now, imagine that you wanted to print each letter <em>and<\/em> its index,\ninstead of just printing the characters.\nHow would you go about doing that?<\/p>\n<p>Perhaps you'll suspect you need to go back to using the range of the length of <code>s<\/code>:<\/p>\n<pre><code class=\"language-py\">s = \"rod\"\nfor idx in range(len(s)):\n    print(f\"Letter {idx} is {s[idx]}\")<\/code><\/pre>\n<pre><code>Letter 0 is r\nLetter 1 is o\nLetter 2 is d<\/code><\/pre>\n<p>And yet, Python provides a built-in that lets us do this while writing the <code>for<\/code> loop in an expressive manner,\njust like before.\nIn order to do that,\nwe use the built-in <code>enumerate<\/code>,\nwhich gives us access to the successive elements <em>and<\/em> their indices:<\/p>\n<pre><code class=\"language-py\">s = \"rod\"\nfor idx, letter in enumerate(s):\n    print(f\"Letter {idx} is {letter}\")<\/code><\/pre>\n<pre><code>Letter 0 is r\nLetter 1 is o\nLetter 2 is d<\/code><\/pre>\n<p>Again, notice how <code>enumerate<\/code> allowed us to write such an expressive loop that clearly communicates our intent:\nwe want to use the indices (<code>idx<\/code>) <em>and<\/em> the letters (<code>letter<\/code>).<\/p>\n<p>In...<\/p>","summary":"In this article we reimplement the built-in `enumerate` in the best way possible.","date_modified":"2025-07-23T16:49:02+02:00","tags":["code review","programming","python"],"image":"\/user\/pages\/02.blog\/enumerate-from-first-principles\/thumbnail.webp"},{"title":"50 shades of sign","date_published":"2022-02-06T00:00:00+01:00","id":"https:\/\/mathspp.com\/blog\/50-shades-of-sign","url":"https:\/\/mathspp.com\/blog\/50-shades-of-sign","content_html":"<p>The Zen of Python says &ldquo;there should be one -- and preferably only one -- obvious way to do it&rdquo;, but what if there's a dozen obvious ways to do it?<\/p>\n\n<figure class=\"image-caption\"><img title=\"My speaker card for the PyCascades conference.\" alt=\"\" src=\"\/images\/7\/7\/3\/e\/3\/773e373075983f6b0ad21991e6c0c2b955c870dd-thumbnail.png\"><figcaption class=\"\">My speaker card for the PyCascades conference.<\/figcaption><\/figure><h2 id=\"preamble\">Preamble<a href=\"#preamble\" class=\"toc-anchor after\" data-anchor-icon=\"#\" aria-label=\"Anchor\"><\/a><\/h2>\n<p>This article is the written version of my talk entitled &ldquo;50 shades of <code>sign<\/code>&rdquo;\nthat I gave for the 2022 edition of the <a href=\"https:\/\/2022.pycascades.com\/\" target=\"_blank\" rel=\"nofollow noopener noreferrer\" class=\"external-link no-image\">PyCascades<\/a> conference.<\/p>\n<p>The slide deck can be found in <a href=\"https:\/\/github.com\/mathspp\/talks\" target=\"_blank\" rel=\"nofollow noopener noreferrer\" class=\"external-link no-image\">this GitHub repository<\/a>\nand the recording can be watched <a href=\"https:\/\/www.youtube.com\/watch?v=FkE-HrxSFCM\" target=\"_blank\" rel=\"nofollow noopener noreferrer\" class=\"external-link no-image\">on YouTube<\/a>.<\/p>\n<h2 id=\"50-shades-of-sign\">50 shades of <code>sign<\/code>\n<a href=\"#50-shades-of-sign\" class=\"toc-anchor after\" data-anchor-icon=\"#\" aria-label=\"Anchor\"><\/a><\/h2>\n<p>The other day I was writing some maths-adjacent code for an algorithm,\nand at some point I needed the function <code>sign<\/code>.\nThe function <code>sign<\/code> is typically well-known, given its simplicity:<\/p>\n<p>The function <code>sign<\/code> (called <code>sgn<\/code> in some languages) accepts a number\nand returns another number:<\/p>\n<ul><li>if the input is positive, it returns 1;<\/li>\n<li>if the input is negative, it returns -1; and<\/li>\n<li>if the input is zero, it returns 0.<\/li>\n<\/ul><p>I don't want to bother you too much with the context of the project,\nso I won't go into the details of <em>why<\/em> I needed this function.<\/p>\n<p>Anyway, I opened up the documentation page for the standard module <code>math<\/code>\nand searched the page for the occurrence of the word &ldquo;sign&rdquo;,\nto see if I could find the function I needed.\nMuch to my surprise, I couldn't find it!<\/p>\n<p>I mean, the letters &ldquo;sign&rdquo; show up 20 times in the <a href=\"https:\/\/docs.python.org\/3\/library\/math.html\" target=\"_blank\" rel=\"nofollow noopener noreferrer\" class=\"external-link no-image\">doc page for <code>math<\/code><\/a>,\nand they mention the sign of numbers a bunch of times,\nbut the function itself doesn't exist!<\/p>\n<p>So I decided to get my hands dirty and thought I'd implement the function myself.\nIn mathematics, the function is usually represented as such:<\/p>\n<p class=\"mathjax mathjax--block\">\\[\n\\text{sgn} ~ x = \\begin{cases}\\begin{aligned}\n&amp;-1, ~ &amp;\\text{if} ~ x &lt; 0, \\\\\n&amp;0, ~ &amp;\\text{if} ~ x = 0, \\\\\n&amp;1, ~ &amp;\\text{if} ~ x &gt; 0.\n\\end{aligned}\\end{cases}\\]<\/p>\n<p>That could be translated almost literally and be turned into a possible implementation of <code>sign<\/code>,\nbut it wouldn't look too good.\nSo, I decided to reorder things a bit and to make use of <code>elif<\/code> and <code>else<\/code> statements:<\/p>\n<pre><code class=\"language-py\">def sign(x):\n    if x &gt; 0:\n        return 1\n    elif x &lt; 0:\n        return -1\n    else:\n        return 0<\/code><\/pre>\n<p>By having the cases <code>&gt; 0<\/code> and <code>&lt; 0<\/code> together, we put the symmetry of the function <code>sign<\/code> under the spotlight, and we use the <code>else<\/code> statement to cover the single case of when <code>x == 0<\/code>, which we can almost interpret as being the edge case of our function.<\/p>\n<p>I looked at my code and felt pretty good about myself,\ngiven that it really looked like I had done a great job!\nSo, I opened the REPL, and thoroughly tested my function:<\/p>\n<pre><code class=\"language-py\">&gt;&gt;&gt; sign(73)\n1\n&gt;&gt;&gt; sign(0)\n0\n&gt;&gt;&gt; sign(-42.42)\n-1<\/code><\/pre>\n<p>&ldquo;Done and dusted&rdquo;, I thought.<\/p>\n<p>But then, I looked at the code I had written and I thought that something was off.\nI mean, I'm being paid to write software and this is what I write?\nIt's...<\/p>","summary":"The Zen of Python says \u201cthere should be one -- and preferably only one -- obvious way to do it\u201d, but what if there are a dozen obvious ways to do it?","date_modified":"2025-07-23T16:49:02+02:00","tags":["code review","mathematics","programming","python"],"image":"\/user\/pages\/02.blog\/50-shades-of-sign\/thumbnail.png"}]}
