
    
        
        
        
                
        
        
        
                
        
        
        
                
        
        
        
                
        
        
        
                
        
        
        
                
        
        
        
                
        
        
        
                
        
        
        
                
        
        
        
            
{"version":"https:\/\/jsonfeed.org\/version\/1","title":"mathspp.com feed","home_page_url":"https:\/\/mathspp.com\/blog\/tags\/dunder-methods","feed_url":"https:\/\/mathspp.com\/blog\/tags\/dunder-methods.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":"Indexable iterables","date_published":"2026-04-03T13:41:00+02:00","id":"https:\/\/mathspp.com\/blog\/indexable-iterables","url":"https:\/\/mathspp.com\/blog\/indexable-iterables","content_html":"<p>Learn how objects are automatically iterable if you implement integer indexing.<\/p>\n\n<h2 id=\"introduction\">Introduction<a href=\"#introduction\" class=\"toc-anchor after\" data-anchor-icon=\"#\" aria-label=\"Anchor\"><\/a><\/h2>\n<p>An <strong>iterable<\/strong> in Python is any object you can traverse through with a <code>for<\/code> loop.\n<strong>Iterables<\/strong> are typically containers and iterating over the iterable object allows you to access the elements of the container.<\/p>\n<p>This article will show you how you can create your own iterable objects through the implementation of integer indexing.<\/p>\n<h2 id=\"indexing-with-getitem\">Indexing with <code>__getitem__<\/code><a href=\"#indexing-with-getitem\" class=\"toc-anchor after\" data-anchor-icon=\"#\" aria-label=\"Anchor\"><\/a><\/h2>\n<p>To make an object that can be indexed you need to implement the method <code>__getitem__<\/code>.<\/p>\n<p>As an example, you'll implement a class <code>ArithmeticSequence<\/code> that represents an <strong>arithmetic sequence<\/strong>, like <span class=\"mathjax mathjax--inline\">\\(5, 8, 11, 14, 17, 20\\)<\/span>.\nAn arithmetic sequence is defined by its first number (<span class=\"mathjax mathjax--inline\">\\(5\\)<\/span>), the step between numbers (<span class=\"mathjax mathjax--inline\">\\(3\\)<\/span>), and the total number of elements (<span class=\"mathjax mathjax--inline\">\\(6\\)<\/span>).\nThe sequence <span class=\"mathjax mathjax--inline\">\\(5, 8, 11, 14, 17, 20\\)<\/span> is <code>seq = ArithmeticSequence(5, 3, 6)<\/code> and <code>seq[3]<\/code> should be <span class=\"mathjax mathjax--inline\">\\(14\\)<\/span>.\nUsing some arithmetic, you can implement indexing in <code>__getitem__<\/code> directly:<\/p>\n<pre><code class=\"language-py\">class ArithmeticSequence:\n    def __init__(self, start: int, step: int, total: int) -&gt; None:\n        self.start = start\n        self.step = step\n        self.total = total\n\n    def __getitem__(self, index: int) -&gt; int:\n        if not 0 &lt;= index &lt; self.total:\n            raise IndexError(f\"Invalid index {index}.\")\n\n        return self.start + index * self.step\n\nseq = ArithmeticSequence(5, 3, 6)\nprint(seq[3])  # 14<\/code><\/pre>\n<h2 id=\"turning-an-indexable-object-into-an-iterable\">Turning an indexable object into an iterable<a href=\"#turning-an-indexable-object-into-an-iterable\" class=\"toc-anchor after\" data-anchor-icon=\"#\" aria-label=\"Anchor\"><\/a><\/h2>\n<p>If your object accepts integer indices, then it is <em>automatically<\/em> an iterable.\nIn fact, you can already iterate over the sequence you created above by simply using it in a <code>for<\/code> loop:<\/p>\n<pre><code class=\"language-py\">for value in seq:\n    print(value, end=\", \")\n# 5, 8, 11, 14, 17, 20,<\/code><\/pre>\n<h2 id=\"how-python-distinguishes-iterables-from-non-iterables\">How Python distinguishes iterables from non-iterables<a href=\"#how-python-distinguishes-iterables-from-non-iterables\" class=\"toc-anchor after\" data-anchor-icon=\"#\" aria-label=\"Anchor\"><\/a><\/h2>\n<p>You might ask yourself &ldquo;how does Python inspect <code>__getitem__<\/code> to see it uses numeric indices?&rdquo;\nIt doesn't!\nIf your object implements <code>__getitem__<\/code> and you try to use it as an iterable, Python will <em>try<\/em> to iterate over it.\nIt either works or it doesn't!<\/p>\n<p>To illustrate this point, you can define a class <code>DictWrapper<\/code> that wraps a dictionary and implements <code>__getitem__<\/code> by just grabbing the corresponding item out of a dictionary:<\/p>\n<pre><code class=\"language-py\">class DictWrapper:\n    def __init__(self, values):\n        self.values = values\n\n    def __getitem__(self, index):\n        return self.values[index]<\/code><\/pre>\n<p>Since <code>DictWrapper<\/code> implements <code>__getitem__<\/code>, if an instance of <code>DictWrapper<\/code> just <em>happens<\/em> to have some integer keys (starting at <code>0<\/code>) then you'll be able to iterate partially over the dictionary:<\/p>\n<pre><code class=\"language-py\">d1 = DictWrapper({0: \"hey\", 1: \"bye\", \"key\": \"value\"})\n\nfor value in d1:\n    print(value)<\/code><\/pre>\n<pre><code class=\"language-pycon\">hey\nbye\nTraceback (most recent call last):\n  File \"&lt;python-input-25&gt;\", line 3, in &lt;module&gt;\n    for value in d1:\n                 ^^\n  File \"&lt;python-input-18&gt;\", line 6, in __getitem__\n    return self.values[index]\n           ~~~~~~~~~~~^^^^^^^\nKeyError: 2<\/code><\/pre>\n<p>What's interesting is that you can see explicitly that Python tried to index the object <code>d<\/code> with the key <code>2<\/code> and it didn't work.\nIn the <code>ArithmeticSequence<\/code> above, you didn't get an error because you raised <code>IndexError<\/code> when you reached the end and that's how Python understood the iteration was done.\nIn this case, since you get a <code>KeyError<\/code>, Python doesn't understand what's going on and just...<\/p>","summary":"Learn how objects are automatically iterable if you implement integer indexing.","date_modified":"2026-04-03T15:09:51+02:00","tags":["python","programming","dunder methods"],"image":"\/user\/pages\/02.blog\/indexable-iterables\/thumbnail.webp"},{"title":"Dipping my toes in metaprogramming","date_published":"2025-05-30T11:48:00+02:00","id":"https:\/\/mathspp.com\/blog\/dipping-my-toes-in-metaprogramming","url":"https:\/\/mathspp.com\/blog\/dipping-my-toes-in-metaprogramming","content_html":"<p>Dip your toes in metaprogramming and learn about <code>__init__<\/code>'s big brother, the dunder method <code>__new__<\/code>.<\/p>\n\n<p>This is the written version of <a href=\"https:\/\/2025.pycon.it\/en\/event\/dipping-my-toes-in-metaprogramming\" target=\"_blank\" rel=\"nofollow noopener noreferrer\" class=\"external-link no-image\">my PyCon Italy 2025 talk<\/a>, which serves as a trial run for myself and as supporting material for folks who attended the talk, or who couldn't attend but are interested in reading about it.<\/p>\n<h2 id=\"cold-opening\">Cold opening<a href=\"#cold-opening\" class=\"toc-anchor after\" data-anchor-icon=\"#\" aria-label=\"Anchor\"><\/a><\/h2>\n<pre><code class=\"language-pycon\">&gt;&gt;&gt; from pathlib import Path\n&gt;&gt;&gt; Path(\".\")\nPosixPath('.')\n&gt;&gt;&gt; type(Path(\".\")) == Path\nFalse<\/code><\/pre>\n<p>Are you comfortable with the short REPL session from above?\nDon't you think it's weird you try to create an instance of the class <code>Path<\/code> but instead you get an instance of the class <code>PosixPath<\/code>?\nI mean, in your computer you might even get something different: an instance of the class <code>WindowsPath<\/code>.<\/p>\n<p>Isn't it funky how the class that we get depends on your context?\nIn this particular case, on your operating system?<\/p>\n<h2 id=\"outline-for-this-talk\">Outline for this talk<a href=\"#outline-for-this-talk\" class=\"toc-anchor after\" data-anchor-icon=\"#\" aria-label=\"Anchor\"><\/a><\/h2>\n<p>I was using the module <code>pathlib<\/code> one day and I thought that this was weird, so today I will show you how this works.\nSadly for you, but thankfully for me, this is not going to be a hardcore metaprogramming talk.\nAfter all, it is called &ldquo;<em>Dipping<\/em> my toes in metaprogramming&rdquo;, not &ldquo;Drowing in metaprogramming&rdquo;.\nWhat this talk is, is an introduction to a very useful metaprogramming tool, that sits right on the fence between crazy, esoteric metaprogramming and general Python knowledge that is likely to help you out sooner or later.<\/p>\n<p>The plan for this talk is to<\/p>\n<ol><li>talk a little bit about parity of integers, in an attempt to show you a similar pattern that is slightly simpler;<\/li>\n<li>go back to talking about paths and the behaviour that they exhibit when instantiated;<\/li>\n<li>talk a little bit about immutability and subclassing immutable types; and<\/li>\n<li>we'll end with some time for Q|A, where you'll be able to ask questions or we'll sit together in awkward silence.<\/li>\n<\/ol><h2 id=\"parity\">Parity<a href=\"#parity\" class=\"toc-anchor after\" data-anchor-icon=\"#\" aria-label=\"Anchor\"><\/a><\/h2>\n<p>To get things rolling, we will start off by trying to emulate the instantiating pattern exhibited by <code>Path<\/code>, but with different classes.\nWe will create a class <code>Number<\/code>, that takes integers, and that produces one of its subclasses:<\/p>\n<ul><li>\n<code>OddNumber<\/code>, if the integer was odd; or<\/li>\n<li>\n<code>EvenNumber<\/code>, if the integer was even.<\/li>\n<\/ul><p>So, we want to build a hierarchy that looks like this:<\/p>\n<pre><code class=\"language-py\">class Number:\n    ...\n\nclass EvenNumber(Number): ...\nclass OddNumber(Number): ...<\/code><\/pre>\n<p>And the point is that, when you instantiate the class <code>Number<\/code>, you get an instance of <code>EvenNumber<\/code> or <code>OddNumber<\/code>, depending on the parity of the argument:<\/p>\n<pre><code class=\"language-py\">print(type(Number(2)))  # &lt;class '__main__.EvenNumber'&gt;<\/code><\/pre>\n<p>Now, when trying to solve this problem, you might start by writing this code:<\/p>\n<pre><code class=\"language-py\">class Number:\n    def __init__(self, value):\n        ...\n\nclass EvenNumber(Number): ...\nclass OddNumber(Number): ...<\/code><\/pre>\n<p>And now you're thinking &ldquo;What the hell do I write in <code>Number.__init__<\/code>?&rdquo;.\nBut, the truth is...\nInside <code>Number.__init__<\/code> it's already too late for whatever you need to do!\nThe argument <code>self<\/code> is already a reference to an object whose type is <code>Number<\/code> and you can't &ldquo;hot-swap&rdquo;...<\/p>","summary":"Dip your toes in metaprogramming and learn about `__init__`&#039;s big brother, the dunder method `__new__`.","date_modified":"2025-07-23T16:49:02+02:00","tags":["dunder methods","metaprogramming","programming","python"],"image":"\/user\/pages\/02.blog\/dipping-my-toes-in-metaprogramming\/thumbnail.webp"},{"title":"TIL #109 \u2013 Unpacking kwargs with custom objects","date_published":"2025-01-05T14:34:00+01:00","id":"https:\/\/mathspp.com\/blog\/til\/unpacking-kwargs-with-custom-objects","url":"https:\/\/mathspp.com\/blog\/til\/unpacking-kwargs-with-custom-objects","content_html":"<p>Today I learned how to allow my custom objects to be unpacked into keyword arguments like '**kwargs'.<\/p>\n\n<h2 id=\"unpacking-kwargs-with-custom-objects\">Unpacking kwargs with custom objects<a href=\"#unpacking-kwargs-with-custom-objects\" class=\"toc-anchor after\" data-anchor-icon=\"#\" aria-label=\"Anchor\"><\/a><\/h2>\n<p>If you have a dictionary, you can use the <code>**<\/code> syntax to unpack its keys and values.\nFor example, you can use that to merge two dictionaries:<\/p>\n<pre><code class=\"language-py\">d_en = {1: \"one\", 2: \"two\"}\nd_pt = {2: \"dois\", 3: \"tr\u00eas\"}\nd = {**d_en, **d_pt}\nprint(d)  # {1: 'one', 2: 'dois', 3: 'tr\u00eas'}<\/code><\/pre>\n<p>This can also be used to unpack a dictionary into keyword arguments:<\/p>\n<pre><code class=\"language-py\">def foo(first, middle, last):\n    return f\"{first} {middle} {last}\"\n\nname_bits = {\n    \"last\": \"Potter\",\n    \"middle\": \"James\",\n    \"first\": \"Harry\",\n}\n\nprint(foo(**name_bits))  # Harry James Potter<\/code><\/pre>\n<p>If you want to be able to use the syntax <code>**<\/code> to unpack your own classes into keyword value pairs, your class must implement the method <code>keys<\/code> and <a href=\"\/blog\/pydonts\/dunder-methods\">the dunder method <code>__getitem__<\/code><\/a>.<\/p>\n<p>The method <code>keys<\/code> must return an iterable with the keys your object is aware of and the dunder method <code>__getitem__<\/code> must be able to return the values associated with the given keys:<\/p>\n<pre><code class=\"language-py\">class HarryPotter:  # A bit of a silly example!\n    def keys(self):\n        return [\"first\", \"middle\", \"last\"]\n\n    def __getitem__(self, key):\n        if key == \"first\":\n            return \"Harry\"\n        elif key == \"middle\":\n            return \"James\"\n        elif key == \"last\":\n            return \"Potter\"\n        else:\n            raise KeyError()\n\nprint(foo(**HarryPotter()))  # Harry James Potter<\/code><\/pre>","summary":"Today I learned how to allow my custom objects to be unpacked into keyword arguments like &#039;**kwargs&#039;.","date_modified":"2025-10-20T22:34:56+02:00","tags":["dunder methods","python","programming"],"image":"\/user\/pages\/02.blog\/04.til\/109.unpacking-kwargs-with-custom-objects\/thumbnail.webp"},{"title":"Customising object creation with __new__","date_published":"2024-07-24T16:00:00+02:00","id":"https:\/\/mathspp.com\/blog\/customising-object-creation-with-__new__","url":"https:\/\/mathspp.com\/blog\/customising-object-creation-with-__new__","content_html":"<p>The dunder method <code>__new__<\/code> is used to customise object creation and is a core stepping stone in understanding metaprogramming in Python.<\/p>\n\n<p>The <a href=\"\/blog\/pydonts\/dunder-methods\">dunder method<\/a> <code>__new__<\/code> is a static method that creates new instances of your class and, therefore, can be used to customise that process.<\/p>\n<p>The dunder methods <code>__init__<\/code> and <code>__new__<\/code> can look quite similar at first sight.\n<a href=\"\/blog\/object-initialisation-with-__init__\">The dunder method <code>__init__<\/code><\/a> will <em>initialise<\/em> your instance of your class, but that instance must be created before it can be initialised, and that's the job of the dunder method <code>__new__<\/code>.<\/p>\n<h2 id=\"arguments-of-the-dunder-method-new\">Arguments of the dunder method <code>__new__<\/code><a href=\"#arguments-of-the-dunder-method-new\" class=\"toc-anchor after\" data-anchor-icon=\"#\" aria-label=\"Anchor\"><\/a><\/h2>\n<p>The dunder method <code>__new__<\/code> accepts, as arguments, the class we are trying to create an instance of and all of the arguments passed to the class constructor, as shown in the snippet below:<\/p>\n<pre><code class=\"language-py\">class C:\n    def __new__(cls, *args, **kwargs):\n        print(cls, args, kwargs)\n        return super().__new__(cls)\n\nC()  # &lt;class '__main__.C'&gt; () {}\nC(73, True, a=15)  # &lt;class '__main__.C'&gt; (73, True) {'a': 15}<\/code><\/pre>\n<p>The return statement includes <code>super().__new__(cls)<\/code>, which is the typical way in which the object we want to create is brought to life.<\/p>\n<h2 id=\"the-return-value-of-the-dunder-method-new\">The return value of the dunder method <code>__new__<\/code><a href=\"#the-return-value-of-the-dunder-method-new\" class=\"toc-anchor after\" data-anchor-icon=\"#\" aria-label=\"Anchor\"><\/a><\/h2>\n<p>The dunder method <code>__new__<\/code> can return any object whatsoever and the return value of the dunder method <code>__new__<\/code> is the result we get when we instantiate the class.<\/p>\n<p>For example, if we create a class <code>C<\/code> whose dunder method <code>__new__<\/code> returns 73, then whenever we try to instantiate the class <code>C<\/code> we get the number 73:<\/p>\n<pre><code class=\"language-py\">class C:\n    def __new__(cls):\n        return 73\n\nc = C()\nprint(c)  # 73\nprint(type(c))  # int<\/code><\/pre>\n<p>Usually, the dunder method <code>__new__<\/code> will return an instance of the class it's in.\nWhen that is the case, Python will automatically call the dunder method <code>__init__<\/code> on the object that was returned and it will pass along the arguments that were specified in the class constructor.\nSo, if <code>__init__<\/code> gets called, it will receive the same arguments that <code>__new__<\/code> received.<\/p>\n<p>This snippet of code shows that <code>__init__<\/code> only gets called when the return value is an instance of the class where the method <code>__new__<\/code> is defined:<\/p>\n<pre><code class=\"language-py\">class C:\n    def __new__(cls, *, return_73):\n        if return_73:\n            return 73\n        else:\n            return super().__new__(cls)\n\n    def __init__(self, *args, **kwargs):\n        print(\"__init__!\")\n\nx = C(return_73=True)\nprint(x)  # 73\ny = C(return_73=False)  # __init__!\nprint(y)  # &lt;__main__.C object at 0x4ac5a507510&gt;<\/code><\/pre>\n<p>It is relevant to note that Python will call <code>__init__<\/code> on the object returned even if it's an instance of a <em>subclass<\/em> of the class where the method <code>__new__<\/code> is running!<\/p>\n<p>In the snippet below, we create the class <code>C<\/code> and its subclass <code>D<\/code>.\n<code>C<\/code> defines the dunder method <code>__new__<\/code> and both classes define their respective dunder methods <code>__init__<\/code>.\nWhen we create an instance of <code>C<\/code>, we actually get an instance of <code>D<\/code> and the dunder method <code>D.__init__<\/code> gets called automatically:<\/p>\n<pre><code class=\"language-py\">class C:\n    def __new__(cls):\n        return super().__new__(D)\n\n    def __init__(self):\n        print(\"C.__init__\")\n\nclass D(C):\n    def __init__(self):\n        print(\"D.__init__\")\n\nd = C()  # D.__init__\nprint(type(d))  # &lt;class '__main__.D'&gt;<\/code><\/pre>\n<p>This may look a bit weird but it's actually a pattern that is...<\/p>","summary":"The dunder method __new__ is used to customise object creation and is a core stepping stone in understanding metaprogramming in Python.","date_modified":"2025-07-23T16:49:02+02:00","tags":["dunder methods","metaprogramming","oop","programming","python"],"image":"\/user\/pages\/02.blog\/customising-object-creation-with-__new__\/thumbnail.webp"},{"title":"Case-insensitive string class","date_published":"2024-07-24T12:00:00+02:00","id":"https:\/\/mathspp.com\/blog\/case-insensitive-string-class","url":"https:\/\/mathspp.com\/blog\/case-insensitive-string-class","content_html":"<p>This article shows how you can create a case-insensitive string class using some basic meta programming with the dunder method <code>__new__<\/code>.<\/p>\n\n<p>In this article we want to implement a case-insensitive string class, that we will call <code>CIStr<\/code>, such that the comparisons between an instance of <code>CIStr<\/code> and a regular string, or between two <code>CIStr<\/code> instances, are done in a case-insensitive way.<\/p>\n<p>Here are two examples of what we're looking for:<\/p>\n<pre><code class=\"language-pycon\">&gt;&gt;&gt; CIStr(\"Hello\") == \"heLLO\"\nTrue\n&gt;&gt;&gt; \"heLLO\" == CIStr(\"Hello\")\nTrue<\/code><\/pre>\n<h2 id=\"case-insensitive-equality-comparison\">Case-insensitive equality comparison<a href=\"#case-insensitive-equality-comparison\" class=\"toc-anchor after\" data-anchor-icon=\"#\" aria-label=\"Anchor\"><\/a><\/h2>\n<p><a href=\"\/blog\/how-to-work-with-case-insensitive-strings\">To compare two strings in a case-insensitive way, we need to use the string method <code>casefold<\/code><\/a>.\nSo, when we implement our class <code>CIStr<\/code>, its <code>__eq__<\/code> and <code>__ne__<\/code> methods should use <code>casefold<\/code> on both string values before comparing them:<\/p>\n<pre><code class=\"language-py\">class CIStr(str):\n    def __eq__(self, other):\n        return self.casefold() == other.casefold()\n\n    def __ne__(self, other):\n        return str.__ne__(self.casefold(), other.casefold())\n\nprint(CIStr(\"hello\") == \"HELlo\")  # True<\/code><\/pre>\n<p>This implementation of <code>__eq__<\/code> works because <code>self.casefold()<\/code> will produce a standard string, which is then compared to <code>other.casefold()<\/code> through the default dunder method <code>__eq__<\/code>, not the one we defined here.\nIf we end up changing the <code>CIStr<\/code> string methods to also return case-insensitive strings, then we may need to be more explicit about the fact that we want to use <code>str.__eq__<\/code> after casefolding both strings:<\/p>\n<pre><code class=\"language-py\">class CIStr(str):\n    def __eq__(self, other):\n        return str.__eq__(self.casefold(), other.casefold())\n\nprint(CIStr(\"hello\") == \"HELlo\")  # True<\/code><\/pre>\n<p>If we didn't do this in the final implementation shown here we would hit an infinite recursion loop.<\/p>\n<h2 id=\"all-case-insensitive-comparisons\">All case-insensitive comparisons<a href=\"#all-case-insensitive-comparisons\" class=\"toc-anchor after\" data-anchor-icon=\"#\" aria-label=\"Anchor\"><\/a><\/h2>\n<p>To make sure that all comparisons are case-insensitive, we also need to take care of the comparison operators <code>&lt;<\/code>, <code>&lt;=<\/code>, <code>&gt;<\/code>, and <code>&gt;=<\/code>.\nWe could think of using <code>functools.total_ordering<\/code> but that will not work because <code>str<\/code> already defines the comparison dunder methods and we need to override their default behaviour:<\/p>\n<pre><code class=\"language-py\">class CIStr(str):\n    def __eq__(self, other):\n        return str.__eq__(self.casefold(), other.casefold())\n\n    def __ne__(self, other):\n        return str.__ne__(self.casefold(), other.casefold())\n\n    def __lt__(self, other):  # &lt;\n        return str.__lt__(self.casefold(), other.casefold())\n\n    def __le__(self, other):  # &lt;=\n        return str.__le__(self.casefold(), other.casefold())\n\n    def __gt__(self, other):  # &lt;=\n        return str.__gt__(self.casefold(), other.casefold())\n\n    def __ge__(self, other):  # &lt;=\n        return str.__ge__(self.casefold(), other.casefold())\n\nprint(CIStr(\"hello\") == \"HELlo\")  # True\nprint(CIStr(\"Hello\") &gt; \"abracadabra\")  # True (H comes after A)<\/code><\/pre>\n<h2 id=\"patch-string-methods-to-accept-and-return-case-insensitive-strin\">Patch string methods to accept and return case-insensitive strings<a href=\"#patch-string-methods-to-accept-and-return-case-insensitive-strin\" class=\"toc-anchor after\" data-anchor-icon=\"#\" aria-label=\"Anchor\"><\/a><\/h2>\n<p>Strings have dozens of methods, like <code>upper<\/code>, <code>startswith<\/code>, and <code>split<\/code>.\nWhat if wanted those methods to work with case-insensitive strings <em>and<\/em> return case-insensitive strings automatically?<\/p>\n<p>For example, as it stands, if we use a method like <code>upper<\/code> on a case-insensitive string, we no longer get a case-insensitive string back.\nBut we can fix this.\nWe can patch every single string method so that:<\/p>\n<ol><li>their arguments are always used casefolded; and<\/li>\n<li>their return values are always case-insensitive strings.<\/li>\n<\/ol><p>This can be achieved if we reimplement every single string method by hand but there is a shorter way.\nTo do this, we define two decorators:<\/p>\n<ol><li>a class decorator (<code>patch_string_methods<\/code>) that will wrap <code>CIStr<\/code> which will traverse the string methods, looking for all of the methods that are not dunder...<\/li><\/ol>","summary":"This article shows how you can create a case-insensitive string class using some basic meta programming with the dunder method __new__.","date_modified":"2025-07-23T16:49:02+02:00","tags":["dunder methods","oop","programming","python"],"image":"\/user\/pages\/02.blog\/case-insensitive-string-class\/thumbnail.webp"},{"title":"Sets as dictionaries with no values","date_published":"2024-05-08T00:00:00+02:00","id":"https:\/\/mathspp.com\/blog\/sets-as-dictionaries-with-no-values","url":"https:\/\/mathspp.com\/blog\/sets-as-dictionaries-with-no-values","content_html":"<p>This article shows how to implement the set built-in at the expense of a dictionary.<\/p>\n\n<p>A set is a built-in container data type in Python that provides fast lookup and insertion.\nIn exchange for that speed, sets are unordered, only hold unique elements, and its elements must be hashable.\nThese characteristics are similar to those of dictionary keys<sup id=\"fnref1:1\"><a href=\"#fn:1\" class=\"footnote-ref\">1<\/a><\/sup> and this shows that a set can actually be implemented as a dictionary with no values.\nIn this article we will explore this relationship between sets and dictionaries by implementing our own set class.<\/p>\n<p>If you are more interested in learning about how to best use sets (and frozensets) in your code, you can <a href=\"\/blog\/pydonts\/set-and-frozenset\">learn how and when to use sets in this article<\/a>.<\/p>\n<h2 id=\"the-internal-representation-of-the-set-values\">The internal representation of the set values<a href=\"#the-internal-representation-of-the-set-values\" class=\"toc-anchor after\" data-anchor-icon=\"#\" aria-label=\"Anchor\"><\/a><\/h2>\n<p>When I talk about a &ldquo;dictionary with no values&rdquo; what I really mean is that the values that we assign to the dictionary keys don't matter.\nIn our implementation of sets we will always use <code>None<\/code> but you can use whatever you want.\nWith that said, we can start by implementing <code>__init__<\/code> and <code>__repr__<\/code> so that we can start instantiating our sets and printing them:<\/p>\n<pre><code class=\"language-py\">class set_:\n    \"\"\"Implementing a set as a dictionary with no values.\"\"\"\n\n    def __init__(self, iterable=None):\n        self.values = {} if iterable is None else dict.fromkeys(iterable)\n\n    def __repr__(self):\n        if not self.values:\n            return \"set_()\"\n        return \"{\" + \", \".join(map(repr, self.values.keys())) + \"}\"\n\nif __name__ == \"__main__\":\n    s = set_(range(10))\n    print(s)  # {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}\n    s = set_()\n    print(s)  # set_()<\/code><\/pre>\n<p>Notice how we're using the class method <code>dict.fromkeys<\/code> to create a dictionary where all keys map to the value <code>None<\/code> inside the dunder method <code>__init__<\/code>:<\/p>\n<pre><code class=\"language-pycon\">&gt;&gt;&gt; dict.fromkeys(range(3))\n{0: None, 1: None, 2: None}<\/code><\/pre>\n<p>In <a href=\"\/blog\/pydonts\/str-and-repr\">the dunder method <code>__repr__<\/code><\/a> we create a special case for when there are no values in the dictionary because we don't want to print <code>{}<\/code> to represent an empty set because <code>{}<\/code> is an empty dictionary!\nNext up, we'll implement methods to add and remove elements from the set.<\/p>\n<h2 id=\"set-methods\">Set methods<a href=\"#set-methods\" class=\"toc-anchor after\" data-anchor-icon=\"#\" aria-label=\"Anchor\"><\/a><\/h2>\n<h3 id=\"constructive-destructive-methods\">Constructive \/ destructive methods<a href=\"#constructive-destructive-methods\" class=\"toc-anchor after\" data-anchor-icon=\"#\" aria-label=\"Anchor\"><\/a><\/h3>\n<p>As you can see from <a href=\"https:\/\/gumroad.com\/l\/cheatsheet-sets\" target=\"_blank\" rel=\"nofollow noopener noreferrer\" class=\"external-link no-image\">my set cheatsheet<\/a>, sets provide the following methods to add\/remove elements:<\/p>\n<ul><li><code>add<\/code> &ndash; adds one element to the set;<\/li>\n<li><code>update<\/code> &ndash; adds all elements from an iterable to the set;<\/li>\n<li><code>pop<\/code> &ndash; removes and returns an arbitrary value from the set;<\/li>\n<li><code>remove<\/code> &ndash; removes the given element from the set and raises a <code>KeyError<\/code> if the element wasn't there to begin with;<\/li>\n<li><code>discard<\/code> &ndash; removes the given element from the set and ignores missing elements; and<\/li>\n<li><code>clear<\/code> &ndash; empties the set.<\/li>\n<\/ul><p>These methods all have straightforward implementations:<\/p>\n<pre><code class=\"language-py\">class set_:\n    # ...\n\n    def add(self, element):\n        \"\"\"Add one element to the set; errors if the element isn't hashable.\"\"\"\n        self.values[element] = None\n\n    def update(self, iterable):\n        \"\"\"Updates the set with all the elements from the given iterable.\"\"\"\n        self.values.update(dict.fromkeys(iterable))\n\n    def pop(self):\n        \"\"\"Remove and return an arbitrary element from the set.\"\"\"\n        item, _ = self.values.popitem()\n        return item\n\n    def remove(self, element):\n        \"\"\"Remove...<\/code><\/pre>","summary":"This article shows how to implement the set built-in at the expense of a dictionary.","date_modified":"2025-11-22T09:33:35+01:00","tags":["dunder methods","programming","python"],"image":"\/user\/pages\/02.blog\/sets-as-dictionaries-with-no-values\/thumbnail.webp"},{"title":"Hold my parentheses light: now with zero sugar","date_published":"2024-04-04T00:00:00+02:00","id":"https:\/\/mathspp.com\/blog\/hold-my-parentheses-light-now-with-zero-sugar","url":"https:\/\/mathspp.com\/blog\/hold-my-parentheses-light-now-with-zero-sugar","content_html":"<p>Explore what Python could look like if we got rid of all of its synthatic sugar.<\/p>\n\n<h1 id=\"hold-my-parentheses-light-now-with-zero-sugar\">Hold my parentheses light: now with zero sugar<a href=\"#hold-my-parentheses-light-now-with-zero-sugar\" class=\"toc-anchor after\" data-anchor-icon=\"#\" aria-label=\"Anchor\"><\/a><\/h1>\n<p>Given a string representing a parenthesised expression like <code>\"(3*(x+42)\"<\/code>, how can we figure out if the expression is correctly parenthesised?<\/p>\n<p>In the <a href=\"\/blog\/hold-my-parentheses\">last article<\/a> I solved this challenge with a funky Python solution.\nIn this article, I want to take a look at the \u201cobvious\u201d solution using a loop:<\/p>\n<pre><code class=\"language-py\">def has_balanced_parens(expression):\n    depth = 0\n    for char in expression:\n        if char == \"(\":\n            depth += 1\n        elif char == \")\":\n            depth -= 1\n            if depth &lt; 0:\n                return False\n    return depth == 0<\/code><\/pre>\n<p>Now, we'll go over this solution and strip it down of its syntactic sugar.\nFirst, we can get rid of all of the arithmetic operators and comparisons because those boil down to calls to some <a href=\"\/blog\/pydonts\/dunder-methods\">dunder methods<\/a>.<\/p>\n<p>We can start by removing the arithmetic operators:<\/p>\n<pre><code class=\"language-py\">def has_balanced_parens(expression):\n    depth = 0\n    for char in expression:\n        if char == \"(\":\n            depth = int.__add__(depth, 1)\n        elif char == \")\":\n            depth = int.__sub__(depth, 1)\n            if depth &lt; 0:\n                return False\n    return depth == 0<\/code><\/pre>\n<p>If you know your way around <a href=\"\/blog\/pydonts\/overloading-arithmetic-operators-with-dunder-methods\">arithmetic dunder methods<\/a>, you'll know that I'm short-circuiting a couple of things, but since <code>depth<\/code> is always an integer and <code>1<\/code> is an integer, I decided to stick with <code>int.__add__<\/code> and <code>int.__sub__<\/code>.<\/p>\n<p>Then, you might think about <code>__iadd__<\/code> and <code>__isub__<\/code>, but <code>int<\/code> does not implement those.<\/p>\n<p>Next, we can do a similar thing for comparison operators:<\/p>\n<pre><code class=\"language-py\">def has_balanced_parens(expression):\n    depth = 0\n    for char in expression:\n        if str.__eq__(char, \"(\"):\n            depth = int.__add__(depth, 1)\n        if str.__eq__(char, \")\"):\n            depth = int.__sub__(depth, 1)\n            if int.__lt__(depth, 0):\n                return False\n    return int.__eq__(depth, 0)<\/code><\/pre>\n<p>Brilliant, right?\nBut that's not all.\nWhy do we even need the conditionals, if we can just use the Boolean values directly?<\/p>\n<pre><code class=\"language-py\">def has_balanced_parens(expression):\n    depth = 0\n    for char in expression:\n        depth = int.__add__(depth, str.__eq__(char, \"(\"))\n        depth = int.__sub__(depth, str.__eq__(char, \")\"))\n        if int.__lt__(depth, 0):\n            return False\n    return int.__eq__(depth, 0)<\/code><\/pre>\n<p><code>if<\/code> statements are not really syntactic sugar in Python, but we could definitely get rid of those two.\nTo conclude, we can get rid of the <code>for<\/code> loop because that's just a <code>while<\/code> loop with extra steps.\nAnd while we're at it, let us replace Booleans with the actual integers they represent:<\/p>\n<pre><code class=\"language-py\">def has_balanced_parens(expression):\n    depth = 0\n    expression_iter = iter(expression)\n    while 1:\n        try:\n            char = next(expression_iter)\n        except StopIteration:\n            break\n        depth = int.__add__(depth, str.__eq__(char, \"(\"))\n        depth = int.__sub__(depth, str.__eq__(char, \")\"))\n        if int.__lt__(depth, 0):\n            return 0\n    return int.__eq__(depth, 0)<\/code><\/pre>\n<p>So, the code above is the solution to our parentheses challenge, written in Python, without any syntactic sugar!<\/p>","summary":"Explore what Python could look like if we got rid of all of its synthatic sugar.","date_modified":"2024-04-22T14:43:43+02:00","tags":["dunder methods","programming","python"],"image":"\/user\/pages\/02.blog\/hold-my-parentheses-light-now-with-zero-sugar\/thumbnail.webp"},{"title":"TIL #092 \u2013 dunder method __init_subclass__","date_published":"2024-03-05T22:00:00+01:00","id":"https:\/\/mathspp.com\/blog\/til\/dunder-method-__init_subclass__","url":"https:\/\/mathspp.com\/blog\/til\/dunder-method-__init_subclass__","content_html":"<p>Today I learned how to use the dunder method <code>__init_subclass__<\/code> to be notified when a class is subclassed.<\/p>\n\n<h2 id=\"init-subclass\"><code>__init_subclass__<\/code><a href=\"#init-subclass\" class=\"toc-anchor after\" data-anchor-icon=\"#\" aria-label=\"Anchor\"><\/a><\/h2>\n<p>The <a href=\"\/blog\/pydonts\/dunder-methods\">dunder method<\/a> <code>__init_subclass__<\/code> is a class method that Python runs when a subclass of that class is instantiated.\nThe snippet below sums it all:<\/p>\n<pre><code class=\"language-py\">class Parent:\n    def __init_subclass__(cls):\n        print(f\"Subclass {cls} was created.\")\n\nclass A(Parent):\n    pass\n\nclass B(A):\n    pass\n\n\"\"\"\nOutput:\nSubclass &lt;class '__main__.A'&gt; was created.\nSubclass &lt;class '__main__.B'&gt; was created.\n\"\"\"<\/code><\/pre>\n<p>The code above shows that when subclasses are created (even if they are not direct subclasses, like the case of <code>B<\/code>) the class method <code>Parent.__init_subclass__<\/code> is called.<\/p>\n<p>The class method <code>__init_subclass__<\/code> will also receive the keyword arguments that you specify on class definition.\nThe snippet below shows this:<\/p>\n<pre><code class=\"language-py\">class Parent:\n    def __init_subclass__(cls, **kwargs):\n        print(f\"Subclass {cls.__name__} created with {kwargs}\")\n\nclass A(Parent, kwarg1=73, kwarg2=True):\n    pass\n\n## Output: Subclass A created with {'kwarg1': 73, 'kwarg2': True}<\/code><\/pre>\n<h3 id=\"metaprogramming-with-init-subclass\">Metaprogramming with <code>__init_subclass__<\/code><a href=\"#metaprogramming-with-init-subclass\" class=\"toc-anchor after\" data-anchor-icon=\"#\" aria-label=\"Anchor\"><\/a><\/h3>\n<p>The point of the dunder method <code>__init_subclass__<\/code> is that a parent class can modify its child classes when they are being created, thus enabling metaprogramming.\nFor example, I needed to use <code>__init_subclass__<\/code> in <a href=\"http:\/\/github.com\/textualize\/textual\" target=\"_blank\" rel=\"nofollow noopener noreferrer\" class=\"external-link no-image\">Textual<\/a> to make sure that all subclasses of a particular class, named <code>Widget<\/code>, had a name that starts with an upper case letter or with an underscore <code>_<\/code>.<\/p>\n<p>You can check the <a href=\"http:\/\/github.com\/textualize\/textual\" target=\"_blank\" rel=\"nofollow noopener noreferrer\" class=\"external-link no-image\">Textual codebase<\/a> for the full context, but this was essentially what I implemented:<\/p>\n<pre><code class=\"language-py\">class BadWidgetName(Exception):\n    \"\"\"Raised when widget names do not satisfy the required restrictions.\"\"\"\n\nclass Widget:\n    def __init_subclass__(cls):\n        name = cls.__name__\n        if not name[0].isupper() or not name.startswith(\"_\"):\n            raise BadWidgetName(\n                f\"Widget class {name!r} must start with an upper case letter or underscore '_'.\"\n            )\n\nclass A(Widget):   # Ok\n    pass\n\nclass _b(Widget):  # Ok\n    pass\n\nclass c(Widget):   # raises BadWidgetName exception.\n    pass<\/code><\/pre>","summary":"Today I learned how to use the dunder method __init_subclass__ to be notified when a class is subclassed.","date_modified":"2025-07-23T16:49:02+02:00","tags":["dunder methods","metaprogramming","programming","python"],"image":"\/user\/pages\/02.blog\/04.til\/092.dunder-method-__init_subclass__\/thumbnail.webp"},{"title":"itertools.batched","date_published":"2023-10-17T00:00:00+02:00","id":"https:\/\/mathspp.com\/blog\/itertools-batched","url":"https:\/\/mathspp.com\/blog\/itertools-batched","content_html":"<p>Learn how <code>batched<\/code> from the module <code>itertools<\/code> works, example use cases, and how to implement it.<\/p>\n\n<p>The module <code>itertools<\/code> introduced a new tool called <code>batched<\/code> in Python 3.12.\n<code>itertools.batched<\/code> lets you iterate over an iterable by going over portions of that iterable &ndash; or batches &ndash; that all have the same size, except possibly for the last one.\nSome <a href=\"#example-use-cases\">example use cases<\/a> include batching API requests or batching data processing.<\/p>\n<p>As a dummy example, consider the snippet below:<\/p>\n<pre><code class=\"language-py\">&gt;&gt;&gt; from itertools import batched\n&gt;&gt;&gt; for batch in batched(\"Hello, world!\", 3):\n...     print(batch)\n...\n('H', 'e', 'l')\n('l', 'o', ',')\n(' ', 'w', 'o')\n('r', 'l', 'd')\n('!',)<\/code><\/pre>\n<p>Notice how the last batch is a tuple with the single character, <code>\"!\"<\/code>.\nThat's because the original input string had length 13 and I asked for batches of size 3, so <code>batched<\/code> served me with four batches of size 3 and the final batch contained the remaining character.<\/p>\n<h2 id=\"example-use-cases\">Example use cases<a href=\"#example-use-cases\" class=\"toc-anchor after\" data-anchor-icon=\"#\" aria-label=\"Anchor\"><\/a><\/h2>\n<p>In this section I will show you a couple of example use cases for <code>itertools.batched<\/code>.\nIf you know of any other good use cases, feel free to leave a comment below or to <a href=\"\/contact-me\">reach out to me<\/a> and I'll include them here.<\/p>\n<h3 id=\"go-over-a-file-in-chunks\">Go over a file in chunks<a href=\"#go-over-a-file-in-chunks\" class=\"toc-anchor after\" data-anchor-icon=\"#\" aria-label=\"Anchor\"><\/a><\/h3>\n<p>If you have a huge file that you need to go over, but you don't need to read the whole file at once, you can use <code>batched<\/code> to go over a set number of lines at a time.\nThe code would look like this:<\/p>\n<pre><code class=\"language-py\">from itertools import batched\n\nwith open(some_file, \"r\") as file:\n    for chunk in batched(file, 25):\n        process_chunk_of_lines(chunk)<\/code><\/pre>\n<p>This could work well if you were looking for some specific line in the file, for example, and you couldn't hold the whole file in memory.\nOf course, in that case, you could probably increase the batch size to something bigger than <code>25<\/code>.<\/p>\n<h3 id=\"chunking-a-response-over-a-socket\">Chunking a response over a socket<a href=\"#chunking-a-response-over-a-socket\" class=\"toc-anchor after\" data-anchor-icon=\"#\" aria-label=\"Anchor\"><\/a><\/h3>\n<p>In contexts like socket communications, it is common to have to chunk your response to a maximum size, so if your message is bigger than some limit, you have to send it in chunks.\nThe code would look something like this:<\/p>\n<pre><code class=\"language-py\">from itertools import batched\n\nfor chunk in batched(raw_data, 1024):\n    sent = socket.send(b\"\".join(chunk))\n    if sent &lt; len(chunk):\n        # Handle the fact that not all data was sent.<\/code><\/pre>\n<p>In this case, you may need to send strings (or bytes) over the socket, and that is why we do <code>b\"\".join(...)<\/code>, because <code>batched<\/code> returns tuples with the elements.<\/p>\n<h3 id=\"iterating-over-substrings\">Iterating over substrings<a href=\"#iterating-over-substrings\" class=\"toc-anchor after\" data-anchor-icon=\"#\" aria-label=\"Anchor\"><\/a><\/h3>\n<p>If you need to use <code>batched<\/code> to split a string, but the final thing you need is substrings, you can use <code>batched<\/code> together with <code>\"\".join<\/code> and <code>map<\/code> to create an iterator that produces substrings of a given length:<\/p>\n<pre><code class=\"language-py\">map(\"\".join, batched(string, length))<\/code><\/pre>\n<p>Here is an example:<\/p>\n<pre><code class=\"language-pycon\">&gt;&gt;&gt; from itertools import batched\n&gt;&gt;&gt; hello_world_substrings = map(\"\".join, batched(\"Hello, world!\", 3))\n&gt;&gt;&gt; for substring in hello_world_substrings:\n...     print(substring)\n...\nHel\nlo,\n wo\nrld\n!<\/code><\/pre>\n<p>This could also work well with the <a href=\"#chunking-a-response-over-a-socket\">socket example<\/a> from above.<\/p>\n<p>Another example where...<\/p>","summary":"Learn how batched from the module itertools works, example use cases, and how to implement it.","date_modified":"2025-07-23T16:49:02+02:00","tags":["dunder methods","generators","modules","programming","python"],"image":"\/user\/pages\/02.blog\/itertools-batched\/thumbnail.webp"},{"title":"Overloading arithmetic operators with dunder methods | Pydon&#039;t \ud83d\udc0d","date_published":"2023-07-31T00:00:00+02:00","id":"https:\/\/mathspp.com\/blog\/pydonts\/overloading-arithmetic-operators-with-dunder-methods","url":"https:\/\/mathspp.com\/blog\/pydonts\/overloading-arithmetic-operators-with-dunder-methods","content_html":"<p>This article shows you how to overload the arithmetic operators in Python with dunder methods.<\/p>\n\n<h2 id=\"introduction\">Introduction<a href=\"#introduction\" class=\"toc-anchor after\" data-anchor-icon=\"#\" aria-label=\"Anchor\"><\/a><\/h2>\n<p>Python lets you override the arithmetic operators like <code>+<\/code> for addition or <code>*<\/code> for multiplication through <a href=\"\/blog\/pydonts\/dunder-methods\">dunder methods<\/a>.\n<a href=\"\/blog\/pydonts\/dunder-methods\">Dunder methods<\/a> are special methods whose name starts and ends with a double underscore (hence, &ldquo;dunder&rdquo;), and some <a href=\"\/blog\/pydonts\/dunder-methods\">dunder methods<\/a> are specific to arithmetic operations.<\/p>\n<p>In this Pydon't, you will learn:<\/p>\n<ul><li>how to implement unary arithmetic operators:\n<ul><li>negation (<code>-p<\/code>);<\/li>\n<li>(<code>+p<\/code>);<\/li>\n<li>absolute value (<code>abs(p)<\/code>); and<\/li>\n<li>inverse (<code>~<\/code>).<\/li>\n<\/ul><\/li>\n<li>how to implement binary arithmetic operators:\n<ul><li>addition (<code>+<\/code>);<\/li>\n<li>subtraction (<code>-<\/code>);<\/li>\n<li>multiplication (<code>*<\/code>);<\/li>\n<li>division (<code>\/<\/code>);<\/li>\n<li>floor division (<code>\/\/<\/code>);<\/li>\n<li>modulo (<code>%<\/code>);<\/li>\n<li>(<code>divmod<\/code>); and<\/li>\n<li>exponentiation (<code>pow<\/code>).<\/li>\n<\/ul><\/li>\n<li>how to implement binary arithmetic operators for bitwise operations:\n<ul><li>left shift (<code>&lt;&lt;<\/code>);<\/li>\n<li>right shift (<code>&gt;&gt;<\/code>);<\/li>\n<li>bitwise and (<code>&amp;<\/code>);<\/li>\n<li>bitwise or (<code>|<\/code>);<\/li>\n<li>bitwise xor (<code>^<\/code>);<\/li>\n<\/ul><\/li>\n<li>what the reflected arithmetic dunder methods are;<\/li>\n<li>what the augmented arithmetic dunder methods are;<\/li>\n<li>what <code>NotImplemented<\/code> is and how it differs from <code>NotImplementedError<\/code>; and<\/li>\n<li>how Python determines which arithmetic dunder method to call.<\/li>\n<\/ul><p>We will start by explaining how dunder methods work and we will give a couple of examples by implementing the unary operators.\nThen, we introduce the mechanics behind the binary arithmetic operators, basing the examples on the binary operator <code>+<\/code>.<\/p>\n<p>After we introduce all the concepts and mechanics that Python uses to handle binary arithmetic operators, we will provide an example of a class that implements all the arithmetic dunder methods that have been mentioned above.<\/p>\n<!--v-->\n<div class=\"notices blue\">\n<p>You can get all the Pydon'ts as a <a href=\"\/books\/pydonts\">free ebook with over +400 pages and hundreds of tips<\/a>. <a href=\"\/books\/pydonts\">Download the ebook &ldquo;Pydon'ts &ndash; write elegant Python code&rdquo; here<\/a>.<\/p>\n<\/div>\n<!--^-->\n<h2 id=\"the-example-we-will-be-using\">The example we will be using<a href=\"#the-example-we-will-be-using\" class=\"toc-anchor after\" data-anchor-icon=\"#\" aria-label=\"Anchor\"><\/a><\/h2>\n<p>The example we will be using throughout this article will be that of a <code>Vector<\/code>.\nA <code>Vector<\/code> will be a class for geometrical vectors, like vectors in 2D, or 3D, and it will provide operations to deal with vectors.\nFor example, by the end of this article, you will have an implementation of <code>Vector<\/code> that lets you do things like these:<\/p>\n<pre><code class=\"language-pycon\">&gt;&gt;&gt; from vector import Vector\n&gt;&gt;&gt; v = Vector(3, 2)\n&gt;&gt;&gt; v + Vector(4, 10)\nVector(7, 12)\n&gt;&gt;&gt; 3 * v\n(9, 6)\n&gt;&gt;&gt; -v\n(-3, -2)<\/code><\/pre>\n<p>Let us go ahead and start!<\/p>\n<p>This is the starting vector for our class <code>Vector<\/code>:<\/p>\n<pre><code class=\"language-py\"># vector.py\nclass Vector:\n    def __init__(self, *coordinates):\n        self.coordinates = coordinates\n\n    def __repr__(self):\n        return f\"Vector{self.coordinates}\"\n\nif __name__ == \"__main__\":\n    print(Vector(3, 2))<\/code><\/pre>\n<p>Running this code will show this output:<\/p>\n<pre><code>Vector(3, 2)<\/code><\/pre>\n<p>This starting vector also shows two dunder methods that we are using right off the bat:<\/p>\n<ol><li>we use <a href=\"\/blog\/object-initialisation-with-__init__\">the dunder method <code>__init__<\/code><\/a> to initialise our <code>Vector<\/code> instance; and<\/li>\n<li>we use <a href=\"\/blog\/pydonts\/str-and-repr\">the dunder method <code>__repr__<\/code><\/a> to provide a string representation of our <code>Vector<\/code> objects.<\/li>\n<\/ol><p>This shows that dunder methods are <strong>not<\/strong> magical.\nThey look funny because of the...<\/p>","summary":"This article shows you how to overload the arithmetic operators in Python with dunder methods.","date_modified":"2025-11-14T12:33:53+01:00","tags":["arithmetic","dunder methods","programming","python"],"image":"\/user\/pages\/02.blog\/02.pydonts\/overloading-arithmetic-operators-with-dunder-methods\/thumbnail.webp"}]}
