
    
        
        
        
                
        
        
        
                
        
        
        
            
{"version":"https:\/\/jsonfeed.org\/version\/1","title":"mathspp.com feed","home_page_url":"https:\/\/mathspp.com\/blog\/tags\/metaprogramming","feed_url":"https:\/\/mathspp.com\/blog\/tags\/metaprogramming.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":"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":"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":"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"}]}
