
    
        
        
        
                
        
        
        
                
        
        
        
                
        
        
        
                
        
        
        
                
        
        
        
                
        
        
        
                
        
        
        
                
        
        
        
                
        
        
        
            
{"version":"https:\/\/jsonfeed.org\/version\/1","title":"mathspp.com feed","home_page_url":"https:\/\/mathspp.com\/blog\/pydonts","feed_url":"https:\/\/mathspp.com\/blog\/pydonts.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":"Functions: a complete reference | Pydon&#039;t \ud83d\udc0d","date_published":"2025-10-06T09:00:00+02:00","id":"https:\/\/mathspp.com\/blog\/pydonts\/functions-a-complete-reference","url":"https:\/\/mathspp.com\/blog\/pydonts\/functions-a-complete-reference","content_html":"<p>This article serves as a complete reference for all the non-trivial things you should know about Python functions.<\/p>\n\n<p>Functions are the basic building block of any Python program you write, and yet, many developers don't leverage their full potential.\nYou will fix that by reading this article.<\/p>\n<p>Knowing how to use the keyword <code>def<\/code> is just the first step towards knowing how to define and use functions in Python.\nAs such, this Pydon't covers everything else there is to learn:<\/p>\n<ul><li>\n<a href=\"#what-goes-into-a-function-and-what-doesn-t\">How to structure and organise functions<\/a>.<\/li>\n<li>\n<a href=\"#the-function-signature\">How to work with a function signature<\/a>, including <a href=\"#ordering-the-parameters\">parameter order<\/a>, <a href=\"#args-and-kwargs\"><code>*args<\/code> and <code>**kwargs<\/code><\/a>, and <a href=\"#positional-only-and-keyword-only-arguments\">the special syntax introduced by <code>*<\/code> and <code>\/<\/code><\/a>.<\/li>\n<li>\n<a href=\"#documenting-functions-with-docstrings\">Best practices to document a function<\/a>.<\/li>\n<li>\n<a href=\"#anonymous-functions\">What anonymous functions are<\/a>, how to define them with the keyword <code>lambda<\/code>, and <a href=\"#use-case-rule-of-thumb\">when to use them<\/a>.<\/li>\n<li>\n<a href=\"#functions-as-objects\">What it means for functions to be objects<\/a> and how to leverage that in your code.<\/li>\n<li>\n<a href=\"#closures\">How closures seem to defy a fundamental rule of scoping in Python<\/a>.<\/li>\n<li>\n<a href=\"#decorators\">How to leverage closures to create the decorator pattern<\/a>.<\/li>\n<li>\n<a href=\"#generator-functions\">What the keyword <code>yield<\/code> is and what generator functions are<\/a>.<\/li>\n<li>\n<a href=\"#asynchronous-functions\">What the keyword <code>async<\/code> is and what asynchronous functions are<\/a>.<\/li>\n<li>\n<a href=\"#partial-function-application\">How partial function application allows you to create new functions from existing functions<\/a>.<\/li>\n<li>\n<a href=\"#not-all-functions-are-functions\">How the term &ldquo;function&rdquo; is overloaded<\/a> and how you can <a href=\"#creating-your-own-callables\">create your own objects that behave like functions<\/a>.<\/li>\n<\/ul><!--v--><div class=\"notices blue\">\n<p>Bookmark this reference for later or download the <a href=\"\/books\/pydonts\">&ldquo;Pydon'ts &ndash; write elegant Python code&rdquo;<\/a> ebook for free.\nThe ebook contains this chapter and many others, including hundreds of tips to help you write better Python code.\n<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=\"what-goes-into-a-function-and-what-doesn-t\">What goes into a function and what doesn't<a href=\"#what-goes-into-a-function-and-what-doesn-t\" class=\"toc-anchor after\" data-anchor-icon=\"#\" aria-label=\"Anchor\"><\/a><\/h2>\n<p>Do not overcrowd your functions with logic for four or five different things.\nA function should do a single thing, and it should do it well, and the name of the function should clearly tell you what your function does.<\/p>\n<p>If you are unsure about whether some piece of code should be a single function or multiple functions, it's best to err on the side of too many functions.\nThat is because a function is a modular piece of code, and the smaller your functions are, the easier it is to compose them together to create more complex behaviours.<\/p>\n<p>Consider the function <code>process_order<\/code> defined below, an exaggerated example that breaks these best practices to make the point clearer.\nWhile it is not incredibly long, it does too many things:<\/p>\n<pre><code class=\"language-py\">def process_order(order):\n    # Validate the order:\n    for item, quantity, price in order:\n        if quantity &lt;= 0:\n            raise ValueError(f\"Cannot buy 0 or less of {item}.\")\n        if price &lt;= 0:\n            raise ValueError(f\"Price must be positive.\")\n\n    # Write the receipt:\n    total = 0\n    with open(\"receipt.txt\", \"w\") as f:\n        for item, quantity, price in order:\n            # This week, yoghurts and batteries are on sale.\n            if \"yoghurt\" in item:\n                price *= 0.8\n            elif \"batteries\" in item:\n                price *= 0.5\n            # Write this line of the receipt:\n            partial...<\/code><\/pre>","summary":"This article is a complete reference for all things related to functions in Python","date_modified":"2025-11-14T12:17:33+01:00","tags":["fp","programming","python"],"image":"\/user\/pages\/02.blog\/02.pydonts\/functions-a-complete-reference\/thumbnail.webp"},{"title":"Decorators | Pydon&#039;t \ud83d\udc0d","date_published":"2025-01-21T18:11:00+01:00","id":"https:\/\/mathspp.com\/blog\/pydonts\/decorators","url":"https:\/\/mathspp.com\/blog\/pydonts\/decorators","content_html":"<p>This article teaches the decorator pattern in Python, why it exists, how to use it, and when to use it to write efficient and idiomatic Python code.<\/p>\n\n<p>The decorator pattern is a functional pattern that Python developers leverage to write more modular and composable functions.\nIn this Pydon't, you will learn exactly why the decorator pattern matters, how to use it, and when to use it.\nYou will also learn how to implement your custom decorators and more advanced use cases of decorators.<\/p>\n<p>In this Pydon't, you will:<\/p>\n<ul><li>learn to recognise when a decorator must be used;<\/li>\n<li>learn to identify the functionality that should be extracted into a decorator;<\/li>\n<li>use an analogy to understand what a decorator is;<\/li>\n<li>implement two simple decorators as initial examples;<\/li>\n<li>learn the full anatomy of a general decorator;<\/li>\n<li>understand why <code>functools.wraps<\/code> should be used when defining decorators;<\/li>\n<li>add arguments to your decorators to make them more useful;<\/li>\n<li>handle the multiple usage patterns that decorators need to handle, inspired by the way the standard library does it;<\/li>\n<li>see that, sometimes, classes can also be used as decorators; and<\/li>\n<li>learn that classes can also be decorated.<\/li>\n<\/ul><!--v--><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=\"a-function-that-did-too-much\">A function that did too much<a href=\"#a-function-that-did-too-much\" class=\"toc-anchor after\" data-anchor-icon=\"#\" aria-label=\"Anchor\"><\/a><\/h2>\n<p>The decorator pattern is a pattern that lets you complement a function with behaviour that is useful but that is orthogonal to the original objective of the function.\nThis pattern is relevant because you do not want to <a href=\"\/blog\/pydonts\/functions-a-complete-reference#what-goes-into-a-function-and-what-doesnt\">overcrowd your functions<\/a>, and at the same time it allows you to define this useful behaviour in a way that is reusable by other functions.<\/p>\n<p>As an example, consider how you might have implemented the mathematical operation factorial before it was introduced in the module <code>math<\/code>:<\/p>\n<pre><code class=\"language-py\"># In modern Python: from math import factorial\ndef factorial(n):\n    r = 1\n    while n &gt; 1:\n        r *= n\n        n -= 1\n    return r<\/code><\/pre>\n<p>If you are calling this function a lot with a few large integers as arguments, you may want to cache the results you compute.\nFor this effect, you may want to use a dictionary that maps inputs to outputs:<\/p>\n<pre><code class=\"language-py\">_factorial_cache = {}\n\ndef factorial(n):\n    if n not in _factorial_cache:\n        _n = n\n        r = 1\n        while _n &gt; 1:\n            r *= _n\n            _n -= 1\n        _factorial_cache[n] = r\n\n    return _factorial_cache[n]<\/code><\/pre>\n<p>This solution is far from ideal, since you introduced a function cache that is only loosely coupled to the function it's relevant for, while also introducing code in the function that is not really relevant for the original objective of the function.<\/p>\n<p>Instead of baking caching into the function, which is a poor one-time solution for something I might want to do with several functions, I can write a higher-order function that adds caching to any function I want.\nLet me walk you through this transformation.<\/p>\n<h2 id=\"factoring-out-the-orthogonal-behaviour\">Factoring out the orthogonal behaviour<a href=\"#factoring-out-the-orthogonal-behaviour\" class=\"toc-anchor after\" data-anchor-icon=\"#\" aria-label=\"Anchor\"><\/a><\/h2>\n<p>Instead of slapping...<\/p>","summary":"This article teaches the decorator pattern in Python, why it exists, how to use it, and when to use it to write efficient and idiomatic Python code.","date_modified":"2025-11-14T12:33:53+01:00","tags":["fp","programming","python"],"image":"\/user\/pages\/02.blog\/02.pydonts\/decorators\/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"},{"title":"Describing Descriptors | Pydon&#039;t \ud83d\udc0d","date_published":"2023-06-13T00:00:00+02:00","id":"https:\/\/mathspp.com\/blog\/pydonts\/describing-descriptors","url":"https:\/\/mathspp.com\/blog\/pydonts\/describing-descriptors","content_html":"<p>Descriptors are not black magic and this article will show you that.\nIn fact, you use descriptors every day and you don't even know it.<\/p>\n\n<p>(If you are new here and have no idea what a Pydon't is, you may want to read the\n<a href=\"\/blog\/pydonts\/pydont-manifesto\">Pydon't Manifesto<\/a>.)<\/p>\n<h2 id=\"introduction\">Introduction<a href=\"#introduction\" class=\"toc-anchor after\" data-anchor-icon=\"#\" aria-label=\"Anchor\"><\/a><\/h2>\n<p>Descriptors are a piece of the Python world that many will declare as &ldquo;obscure&rdquo;, &ldquo;dark magic&rdquo;, or &ldquo;too complex to bother learning&rdquo;.\nI will show you that this is <em>not<\/em> true.<\/p>\n<p>While we can all agree that descriptors do not belong in an introductory course to Python, descriptors are far from black magic and with a couple of good examples you can understand how they work and what they are useful for.<\/p>\n<p>In this Pydon't, you will<\/p>\n<ul><li>see what a descriptor is;<\/li>\n<li>learn how to implement your own descriptors;<\/li>\n<li>read about descriptor-related <a href=\"\/blog\/pydonts\/dunder-methods\">dunder methods<\/a>;<\/li>\n<li>learn about the descriptor protocol:\n<ul><li><code>__get__<\/code>;<\/li>\n<li><code>__set__<\/code>; and<\/li>\n<li><code>__delete__<\/code>.<\/li>\n<\/ul><\/li>\n<li>see how to use <code>__set_name__<\/code> with descriptors;<\/li>\n<li>understand that descriptors play a key part in the way Python works, for example in:\n<ul><li>methods;<\/li>\n<li>the built-in <code>property<\/code>;<\/li>\n<li>the built-in <code>staticmethod<\/code>; and<\/li>\n<li>the built-in <code>classmethod<\/code>.<\/li>\n<\/ul><\/li>\n<li>be mind blown by the fact that you use descriptors every day (spoiler: functions <em>are<\/em> descriptors!);<\/li>\n<li>study some common use cases for descriptors; and<\/li>\n<li>solve some exercises and challenges to practise.<\/li>\n<\/ul><!--v--><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-problem-that-descriptors-solve\">The problem that descriptors solve<a href=\"#the-problem-that-descriptors-solve\" class=\"toc-anchor after\" data-anchor-icon=\"#\" aria-label=\"Anchor\"><\/a><\/h2>\n<p>Consider the implementation of the class <code>Colour<\/code> below, which contains a <code>hex<\/code> attribute for the hexadecimal representation of the colour:<\/p>\n<pre><code class=\"language-py\">class Colour:\n    def __init__(self, hex):\n        self.hex = hex<\/code><\/pre>\n<p>This class doesn't do much (at least, for now...):<\/p>\n<pre><code class=\"language-pycon\">&gt;&gt;&gt; colour = Colour(\"#f8f8f2\")\n&gt;&gt;&gt; colour.hex\n'#f8f8f2'<\/code><\/pre>\n<p>Now, suppose that you want to add the attributes <code>r<\/code>, <code>g<\/code>, and <code>b<\/code>, respectively for the red, green, and blue, components of the colour.\nThese attributes depend on the value of the hexadecimal representation of the colour, and you <a href=\"\/blog\/pydonts\/properties\">know all about properties<\/a>, so you understand that defining three properties is the way to go, here:<\/p>\n<pre><code class=\"language-py\">class Colour:\n    def __init__(self, hex_string):\n        self.hex = hex_string\n\n    @property\n    def r(self):\n        return int(self.hex[1:3], 16)\n\n    @property\n    def g(self):\n        return int(self.hex[3:5], 16)\n\n    @property\n    def b(self):\n        return int(self.hex[5:7], 16)<\/code><\/pre>\n<p>This works as expected:<\/p>\n<pre><code class=\"language-py\">&gt;&gt;&gt; red = Colour(\"#ff0000\")\n&gt;&gt;&gt; red.r\n255\n&gt;&gt;&gt; red.g, red.b\n(0, 0)<\/code><\/pre>\n<p>If you have an attentive eye, you will notice that the three properties are pretty much the same.\nThe only difference lies in the indices you use when slicing the parameter <code>hex<\/code>.<\/p>\n<p>Descriptors, like properties, let you customise attribute lookup.\nHowever, descriptors give you <em>more<\/em> freedom because you implement a descriptor as a class.\nThis is different from properties that are usually implemented via their getter, setter, and deleter methods.<\/p>\n<p>Later, you will understand that descriptors give you more freedom because properties <em>are<\/em> a specific descriptor.\nIn a way, properties provide a type of descriptor blueprint...<\/p>","summary":"Descriptors are not black magic and this article will show you that.","date_modified":"2025-11-14T12:33:53+01:00","tags":["dunder methods","oop","programming","python"],"image":"\/user\/pages\/02.blog\/02.pydonts\/describing-descriptors\/thumbnail.webp"},{"title":"Properties | Pydon&#039;t \ud83d\udc0d","date_published":"2023-05-14T00:00:00+02:00","id":"https:\/\/mathspp.com\/blog\/pydonts\/properties","url":"https:\/\/mathspp.com\/blog\/pydonts\/properties","content_html":"<p>Learn how to use properties to add dynamic behaviour to your attributes.<\/p>\n\n<p>(If you are new here and have no idea what a Pydon't is, you may want to read the\n<a href=\"\/blog\/pydonts\/pydont-manifesto\">Pydon't Manifesto<\/a>.)<\/p>\n<h2 id=\"introduction\">Introduction<a href=\"#introduction\" class=\"toc-anchor after\" data-anchor-icon=\"#\" aria-label=\"Anchor\"><\/a><\/h2>\n<p>Properties, defined via the <code>property<\/code> built-in, are a Python feature that lets you add dynamic behaviour behind what is typically a static interface: an attribute.\nProperties also have other benefits and use cases, and we will cover them here.<\/p>\n<p>In this Pydon't, you will<\/p>\n<ul><li>understand what a property is;<\/li>\n<li>learn how to implement a property with the built-in <code>property<\/code>;<\/li>\n<li>learn how to use <code>property<\/code> to implement read-only attributes;<\/li>\n<li>see that <code>property<\/code> doesn't have to be used as a decorator;<\/li>\n<li>add setters to your properties;<\/li>\n<li>use setters to do data validation and normalisation;<\/li>\n<li>read about deleters in properties; and<\/li>\n<li>see usages of <code>property<\/code> in the standard library.<\/li>\n<\/ul><!--v--><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=\"what-is-a-property\">What is a property?<a href=\"#what-is-a-property\" class=\"toc-anchor after\" data-anchor-icon=\"#\" aria-label=\"Anchor\"><\/a><\/h2>\n<p>A property is an attribute that is computed dynamically.\nThat's it.\nAnd you will understand what this means in a jiffy!<\/p>\n<h3 id=\"the-problem\">The problem<a href=\"#the-problem\" class=\"toc-anchor after\" data-anchor-icon=\"#\" aria-label=\"Anchor\"><\/a><\/h3>\n<p>This is a class <code>Person<\/code> with three vanilla attributes:<\/p>\n<pre><code class=\"language-py\">class Person:\n    def __init__(self, first, last):\n        self.first = first\n        self.last = last\n        self.name = f\"{self.first} {self.last}\"\n\njohn = Person(\"John\", \"Doe\")<\/code><\/pre>\n<p>However, there is an issue with the implementation.\nCan you see what is the issue with this implementation?<\/p>\n<p>I'll give you a hint:<\/p>\n<pre><code class=\"language-pycon\">&gt;&gt;&gt; john = Person(\"John\", \"Doe\")\n&gt;&gt;&gt; john.name\n'John Doe'\n&gt;&gt;&gt; john.last = \"Smith\"\n&gt;&gt;&gt; john.name\n## ?<\/code><\/pre>\n<p>When you implement <code>name<\/code> as a regular attribute, it can go out of sync when you change the attributes upon which <code>name<\/code> depended on.<\/p>\n<p>How do we fix this?\nWell, we could provide methods that the user can use to set the first and last names of the <code>Person<\/code> instance, and those methods could keep <code>name<\/code> in sync:<\/p>\n<pre><code class=\"language-py\">class Person:\n    def __init__(self, first, last):\n        self.first = first\n        self.last = last\n        self.name = f\"{self.first} {self.last}\"\n\n    def set_first(self, first):\n        self.first = first\n        self.name = f\"{self.first} {self.last}\"\n\n    def set_last(self, last):\n        self.last = last\n        self.name = f\"{self.first} {self.last}\"\n\njohn = Person(\"John\", \"Doe\")<\/code><\/pre>\n<p>This works:<\/p>\n<pre><code class=\"language-pycon\">&gt;&gt;&gt; john = Person(\"John\", \"Doe\")\n&gt;&gt;&gt; john.name\n'John Doe'\n&gt;&gt;&gt; john.set_first(\"Charles\")\n&gt;&gt;&gt; john.name\n'Charles Doe'<\/code><\/pre>\n<p>However, we had to add two methods that look pretty much the same...\nAnd this would get worse if we introduced an attribute for middle names, for example...\nEssentially, this isn't a very Pythonic solution &ndash; it isn't very elegant.\n(Or, at least, we can do better!)<\/p>\n<p>There is another alternative...\nInstead of updating <code>name<\/code> when the other attributes are changed, we could add a method that computes the name of the user on demand:<\/p>\n<pre><code class=\"language-py\">class Person:\n    def __init__(self, first, last):\n        self.first = first\n        self.last = last\n\n    def get_name(self):\n        return f\"{self.first} {self.last}\"<\/code><\/pre>\n<p>This also works:<\/p>\n<pre><code class=\"language-pycon\">&gt;&gt;&gt; john = Person(\"John\", \"Doe\")\n&gt;&gt;&gt; john.get_name()\n'John Doe'\n&gt;&gt;&gt; john.first = \"Charles\"\n&gt;&gt;&gt; john.get_name()\n'Charles Doe'<\/code><\/pre>\n<p>But this isn't very elegant,...<\/p>","summary":"Learn how to use properties to add dynamic behaviour to your attributes.","date_modified":"2025-11-14T12:33:53+01:00","tags":["oop","programming","python"],"image":"\/user\/pages\/02.blog\/02.pydonts\/properties\/thumbnail.webp"},{"title":"Dunder methods | Pydon&#039;t \ud83d\udc0d","date_published":"2022-07-09T00:00:00+02:00","id":"https:\/\/mathspp.com\/blog\/pydonts\/dunder-methods","url":"https:\/\/mathspp.com\/blog\/pydonts\/dunder-methods","content_html":"<p>This is an introduction to dunder methods in Python,\nto help you understand what they are and what they are for.<\/p>\n\n<p>(If you are new here and have no idea what a Pydon't is, you may want to read the\n<a href=\"\/blog\/pydonts\/pydont-manifesto\">Pydon't Manifesto<\/a>.)<\/p>\n<h2 id=\"introduction\">Introduction<a href=\"#introduction\" class=\"toc-anchor after\" data-anchor-icon=\"#\" aria-label=\"Anchor\"><\/a><\/h2>\n<p>Python is a language that has a rich set of built-in functions and operators that work really well with the built-in types.\nFor example, the operator <code>+<\/code> works on numbers, as addition, but it also works on strings, lists, and tuples, as concatenation:<\/p>\n<pre><code class=\"language-pycon\">&gt;&gt;&gt; 1 + 2.3\n3.3\n&gt;&gt;&gt; [1, 2, 3] + [4, 5, 6]\n[1, 2, 3, 4, 5, 6]<\/code><\/pre>\n<p>But what is it that defines that <code>+<\/code> is addition for numbers (integers and floats)\nand concatenation for lists, tuples, strings?\nWhat if I wanted <code>+<\/code> to work on other types?\nCan I do that?<\/p>\n<p>The short answer is &ldquo;yes&rdquo;, and that happens through <strong>dunder methods<\/strong>,\nthe object of study in this Pydon't.\nIn this Pydon't, you will<\/p>\n<ul><li>understand what are dunder methods;<\/li>\n<li>why they are called like that;<\/li>\n<li>see various useful dunder methods;<\/li>\n<li>learn about what dunder methods correspond to what built-ins;<\/li>\n<li>write your own dunder methods for example classes; and<\/li>\n<li>realise that dunder methods are like any other method you have written before.<\/li>\n<\/ul><!--v--><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=\"what-are-dunder-methods\">What are dunder methods?<a href=\"#what-are-dunder-methods\" class=\"toc-anchor after\" data-anchor-icon=\"#\" aria-label=\"Anchor\"><\/a><\/h2>\n<p>In Python, <strong>dunder methods are methods that allow instances of a class to interact with the built-in functions and operators<\/strong> of the language.\nThe word &ldquo;dunder&rdquo; comes from &ldquo;double underscore&rdquo;, because the names of dunder methods start and end with two underscores,\nfor example <code>__str__<\/code> or <code>__add__<\/code>.\nTypically, dunder methods are not invoked directly by the programmer, making it look like they are called by magic.\nThat is why dunder methods are also referred to as &ldquo;magic methods&rdquo; sometimes.<sup id=\"fnref1:1\"><a href=\"#fn:1\" class=\"footnote-ref\">1<\/a><\/sup><\/p>\n<p>Dunder methods are not called magically, though.\nThey are just called implicitly by the language, at specific times that are well-defined,\nand that depend on the dunder method in question.<\/p>\n<h3 id=\"the-dunder-method-everyone-knows\">The dunder method everyone knows<a href=\"#the-dunder-method-everyone-knows\" class=\"toc-anchor after\" data-anchor-icon=\"#\" aria-label=\"Anchor\"><\/a><\/h3>\n<p>If you have defined classes in Python, you are bound to have crossed paths with a dunder method: <code>__init__<\/code>.\n<strong>The dunder method <code>__init__<\/code> is responsible for <em>initialising<\/em> your instance of the class<\/strong>,\nwhich is why it is in there that you usually set a bunch of attributes related to arguments the class received.<\/p>\n<p>For example, if you were creating an instance of a class <code>Square<\/code>,\nyou would create the attribute for the side length in <code>__init__<\/code>:<\/p>\n<pre><code class=\"language-py\">class Square:\n    def __init__(self, side_length):\n        \"\"\"__init__ is the dunder method that INITialises the instance.\n\n        To create a square, we need to know the length of its side,\n        so that will be passed as an argument later, e.g. with Square(1).\n        To make sure the instance knows its own side length,\n        we save it with self.side_length = side_length.\n        \"\"\"\n        print(\"Inside...<\/code><\/pre>","summary":"This is an introduction to dunder methods in Python, to help you understand what they are and what they are for.","date_modified":"2025-11-14T12:33:53+01:00","tags":["dunder methods","programming","python"],"image":"\/user\/pages\/02.blog\/02.pydonts\/dunder-methods\/thumbnail.webp"},{"title":"Why mastering Python is impossible, and why that&#039;s ok | Pydon&#039;t \ud83d\udc0d","date_published":"2021-12-04T00:00:00+01:00","id":"https:\/\/mathspp.com\/blog\/pydonts\/why-mastering-python-is-impossible","url":"https:\/\/mathspp.com\/blog\/pydonts\/why-mastering-python-is-impossible","content_html":"<p>Let me tell you why it is impossible to truly master Python, but also show you how to get as close to it as possible.<\/p>\n\n<script async src=\"https:\/\/platform.twitter.com\/widgets.js\" charset=\"utf-8\"><\/script><figure class=\"image-caption\"><img title=\"Photo by Migle Siauciulyte on Unsplash.\" alt=\"A rocky trail heading up a hill.\" src=\"\/images\/8\/5\/b\/2\/6\/85b26a0e63bf7425314475be3881eab4b438c434-thumbnail.png\"><figcaption class=\"\">Photo by Migle Siauciulyte on Unsplash.<\/figcaption><\/figure><h2 id=\"introduction\">Introduction<a href=\"#introduction\" class=\"toc-anchor after\" data-anchor-icon=\"#\" aria-label=\"Anchor\"><\/a><\/h2>\n<p><a href=\"https:\/\/en.wikipedia.org\/wiki\/Outliers_(book)\" target=\"_blank\" rel=\"nofollow noopener noreferrer\" class=\"external-link no-image\">It has been said<\/a> that you need 10,000 hours to master a skill.\nI won't dispute if that's true or not.\nWhat I'll tell you is that, even if that's true,\nI'm not sure it applies to Python!<\/p>\n<p>In this Pydon't, I'll explain why I think you can't really <em>master<\/em> Python,\nbut I'll also tell you why I think that's ok:\nI'll give you a series of practical tips that you can use to make sure\nyou keep improving your Python knowledge.<\/p>\n<p>Finally, by the end of the Pydon't,\nI'll share a little anecdote from my own personal experience with Python,\nto support my claims.<\/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=\"to-master-verb\">&ldquo;to master&rdquo;, verb<a href=\"#to-master-verb\" class=\"toc-anchor after\" data-anchor-icon=\"#\" aria-label=\"Anchor\"><\/a><\/h2>\n<p>Here's the <a href=\"https:\/\/www.oxfordlearnersdictionaries.com\/definition\/english\/master_2\" target=\"_blank\" rel=\"nofollow noopener noreferrer\" class=\"external-link no-image\">dictionary definition<\/a> of the verb &ldquo;to master&rdquo;:<\/p>\n<blockquote>\n<p>&ldquo;master&rdquo;, verb &ndash; to learn or understand something completely<\/p>\n<\/blockquote>\n<p>From my personal experience,\nthere are two levels at which I believe one cannot master Python;\nI'll lay both of them down now.<\/p>\n<h3 id=\"python-is-an-evolving-language\">Python is an evolving language<a href=\"#python-is-an-evolving-language\" class=\"toc-anchor after\" data-anchor-icon=\"#\" aria-label=\"Anchor\"><\/a><\/h3>\n<p>The Python language is an evolving language: it isn't a finished product.\nAs such, it keeps growing:<\/p>\n<ul><li>new functions get added;<\/li>\n<li>new syntax is introduced;<\/li>\n<li>the standard library changes;<\/li>\n<li>...<\/li>\n<\/ul><p>Therefore, I can never know everything about it!\nAs soon as I think I just learned all the things there are to learn,\nnew things pop up.<\/p>\n<p>This is something I believe in, but it is also almost a philosophical point of view.\nThere is also a practical side to this argument.<\/p>\n<h3 id=\"python-is-just-too-big\">Python is just too big<a href=\"#python-is-just-too-big\" class=\"toc-anchor after\" data-anchor-icon=\"#\" aria-label=\"Anchor\"><\/a><\/h3>\n<p>Not only does the language keep changing,\none can argue that the Python language is already too big for you to be able to master it.<\/p>\n<p>For example, most of us are familiar with the list methods <code>.append<\/code> or <code>.pop<\/code>.\nBut, from my experience, most people aren't familiar with the list methods <code>.copy<\/code>, or <code>.extend<\/code>, for example.\nIn fact, let's do an experiment: can you name the 11 existing list methods?<\/p>\n<p>Scroll to the bottom of the page and write them down as a comment.\nIf not the 11, write down as many as you can remember.<\/p>\n<p>Here are they:<\/p>\n<pre><code class=\"language-py\">&gt;&gt;&gt; [name for name in dir(list) if not name.startswith(\"__\")]\n['append', 'clear', 'copy', 'count', 'extend', 'index', 'insert', 'pop', 'remove', 'reverse', 'sort']<\/code><\/pre>\n<div class=\"notices yellow\">\n<p>No idea what <code>dir<\/code> is? Just <a href=\"#dir-and-help\">scroll down<\/a>.<\/p>\n<\/div>\n<p>Maybe you even knew about all of them,\nbut being able to name them is hard, right?<\/p>\n<p>Let's do a similar thing for strings!\nFirst, jot down as many string methods that you can remember.<\/p>\n<p>Done?<\/p>\n<p>Great.\nNow count them.\nHow many did you get?<\/p>\n<p>Now, how many string methods do you <em>think<\/em> there are?<\/p>\n<p>There are 47 (!) string methods!<\/p>\n<p>Probably, you never even...<\/p>","summary":"Let me tell you why it is impossible to truly master Python, but also show you how to get as close to it as possible.","date_modified":"2025-07-23T16:49:02+02:00","tags":["programming","python"],"image":"\/user\/pages\/02.blog\/02.pydonts\/why-mastering-python-is-impossible\/thumbnail.png"},{"title":"String formatting comparison | Pydon&#039;t \ud83d\udc0d","date_published":"2021-11-19T00:00:00+01:00","id":"https:\/\/mathspp.com\/blog\/pydonts\/string-formatting-comparison","url":"https:\/\/mathspp.com\/blog\/pydonts\/string-formatting-comparison","content_html":"<p>This article compares the three main string formatting methods in Python and suggests which methods to use in each situation.<\/p>\n\n<script async src=\"https:\/\/platform.twitter.com\/widgets.js\" charset=\"utf-8\"><\/script><p>(If you are new here and have no idea what a Pydon't is, you may want to read the\n<a href=\"\/blog\/pydonts\/pydont-manifesto\">Pydon't Manifesto<\/a>.)<\/p>\n<h2 id=\"introduction\">Introduction<a href=\"#introduction\" class=\"toc-anchor after\" data-anchor-icon=\"#\" aria-label=\"Anchor\"><\/a><\/h2>\n<p>The <a href=\"\/blog\/pydonts\/pydont-disrespect-the-zen-of-python\">Zen of Python<\/a> says that<\/p>\n<blockquote>\n<p>&ldquo;There should be one &ndash; and preferably only one &ndash; obvious way to do it.&rdquo;<\/p>\n<\/blockquote>\n<p>And yet, there are three main ways of doing string formatting in Python.\nThis Pydon't will settle the score,\ncomparing these three methods and helping you decide which one is the obvious one to use\nin each situation.<\/p>\n<p>In this Pydon't, you will:<\/p>\n<ul><li>learn about the old C-style formatting with %;<\/li>\n<li>learn about the string method <code>.format<\/code>;<\/li>\n<li>learn about the Python 3.6+ feature of literal string interpolation and f-strings;<\/li>\n<li>understand the key differences between each type of string formatting; and<\/li>\n<li>see where each type of string formatting really shines.<\/li>\n<\/ul><!--v--><div class=\"notices blue\">\n<p>You can now get your <strong>free<\/strong> copy of the ebook &ldquo;Pydon'ts &ndash; Write elegant Python code&rdquo; <a href=\"https:\/\/gum.co\/pydonts\" target=\"_blank\" rel=\"nofollow noopener noreferrer\" class=\"external-link no-image\">on Gumroad<\/a>.<\/p>\n<\/div>\n<!--^-->\n<h2 id=\"string-formatting-rationale\">String formatting rationale<a href=\"#string-formatting-rationale\" class=\"toc-anchor after\" data-anchor-icon=\"#\" aria-label=\"Anchor\"><\/a><\/h2>\n<p>Let's pretend, for a second, that Python had zero ways of doing string formatting.<\/p>\n<p>Now, I have a task for you:\nwrite a function that accepts a programming language name and returns a string\nsaying that said programming language rocks.\nCan you do it?\nAgain, <em>without<\/em> any string formatting whatsoever!<\/p>\n<p>Here is a possible solution:<\/p>\n<pre><code class=\"language-py\">def language_rocks(language):\n    return language + \" rocks!\"\n\n## ---\n&gt;&gt;&gt; language_rocks(\"Python\")\n'Python rocks!'<\/code><\/pre>\n<p>Great job!<\/p>\n<p>Now, write a function that accepts a programming language name and its (estimated) number of users,\nand returns a string saying something along the lines of\n&ldquo;&lt;insert language&gt; rocks! Did you know that &lt;insert language&gt; has around &lt;insert number&gt; users?&rdquo;.<\/p>\n<p>Can you do it?\nRecall that you are <em>not<\/em> supposed to use any string formatting facilities, whatsoever!<\/p>\n<p>Here is a possible solution:<\/p>\n<pre><code class=\"language-py\">def language_info(language, users_estimate):\n    return (\n        language + \" rocks! Did you know that \" + language +\n        \" has around \" + str(users_estimate) + \" users?!\"\n    )\n\n## ---\n&gt;&gt;&gt; language_info(\"Python\", 10)\n'Python rocks! Did you know that Python has around 10 users?!'<\/code><\/pre>\n<p>Notice how that escalated quite quickly:\nthe purpose of our function is still very simple,\nand yet we have a bunch of string concatenations happening all over the place,\njust because we have some pieces of information that we want to merge into the string.<\/p>\n<p>This is what string formatting is for:\nit's meant to make your life easier when you need to put information inside strings.<\/p>\n<h2 id=\"three-string-formatting-methods\">Three string formatting methods<a href=\"#three-string-formatting-methods\" class=\"toc-anchor after\" data-anchor-icon=\"#\" aria-label=\"Anchor\"><\/a><\/h2>\n<p>Now that we've established that string formatting is useful,\nlet's take a look at the three main ways of doing string formatting in Python.<\/p>\n<p>First, here is how you would refactor the function above:<\/p>\n<pre><code class=\"language-py\">## Using C-style string formatting:\ndef language_info_cstyle(language, users_estimate):\n    return (\n        \"%s rocks! Did you know that %s has around %d users?!\" %\n        (language, language, users_estimate)\n    )\n\n## Using the Python 3 `.format` method from strings:\ndef language_info_format(language, users_estimate):\n    return \"{} rocks! Did you know...<\/code><\/pre>","summary":"This article compares the three main string formatting methods in Python and suggests which methods to use in each situation.","date_modified":"2025-11-14T12:33:53+01:00","tags":["programming","python"],"image":"\/user\/pages\/02.blog\/02.pydonts\/string-formatting-comparison\/thumbnail.webp"},{"title":"Pass-by-value, reference, and assignment | Pydon&#039;t \ud83d\udc0d","date_published":"2021-11-03T23:00:00+01:00","id":"https:\/\/mathspp.com\/blog\/pydonts\/pass-by-value-reference-and-assignment","url":"https:\/\/mathspp.com\/blog\/pydonts\/pass-by-value-reference-and-assignment","content_html":"<p>When you call a function in Python and give it some arguments...\nAre they passed by value? No!\nBy reference? No!\nThey're passed by assignment.<\/p>\n\n<script async src=\"https:\/\/platform.twitter.com\/widgets.js\" charset=\"utf-8\"><\/script><p>(If you are new here and have no idea what a Pydon't is, you may want to read the\n<a href=\"\/blog\/pydonts\/pydont-manifesto\">Pydon't Manifesto<\/a>.)<\/p>\n<h2 id=\"introduction\">Introduction<a href=\"#introduction\" class=\"toc-anchor after\" data-anchor-icon=\"#\" aria-label=\"Anchor\"><\/a><\/h2>\n<p>Many traditional programming languages employ either one of two models\nwhen passing arguments to functions:<\/p>\n<ul><li>some languages use the pass-by-value model; and<\/li>\n<li>most of the others use the pass-by-reference model.<\/li>\n<\/ul><p>Having said that, it is important to know the model that Python uses,\nbecause that influences the way your code behaves.<\/p>\n<p>In this Pydon't, you will:<\/p>\n<ul><li>see that Python doesn't use the pass-by-value nor the pass-by-reference models;<\/li>\n<li>understand that Python uses a pass-by-assignment model;<\/li>\n<li>learn about the built-in function <code>id<\/code>;<\/li>\n<li>create a better understanding for the Python object model;<\/li>\n<li>realise that every object has 3 very important properties that define it;<\/li>\n<li>understand the difference between mutable and immutable objects;<\/li>\n<li>learn the difference between shallow and deep copies; and<\/li>\n<li>learn how to use the module <code>copy<\/code> to do both types of object copies.<\/li>\n<\/ul><!--v--><div class=\"notices blue\">\n<p>You can now get your <strong>free<\/strong> copy of the ebook &ldquo;Pydon'ts &ndash; Write elegant Python code&rdquo; <a href=\"https:\/\/gum.co\/pydonts\" target=\"_blank\" rel=\"nofollow noopener noreferrer\" class=\"external-link no-image\">on Gumroad<\/a>.<\/p>\n<\/div>\n<!--^-->\n<h2 id=\"is-python-pass-by-value\">Is Python pass-by-value?<a href=\"#is-python-pass-by-value\" class=\"toc-anchor after\" data-anchor-icon=\"#\" aria-label=\"Anchor\"><\/a><\/h2>\n<p>In the pass-by-value model, when you call a function with a set of arguments,\nthe data is copied into the function.\nThis means that you can modify the arguments however you please and\nthat you won't be able to alter the state of the program\noutside the function.\nThis is not what Python does, Python does not use the pass-by-value model.<\/p>\n<p>Looking at the snippet of code that follows,\nit might look like Python uses pass-by-value:<\/p>\n<pre><code class=\"language-py\">def foo(x):\n    x = 4\n\na = 3\nfoo(a)\nprint(a)\n## 3<\/code><\/pre>\n<p>This looks like the pass-by-value model because we gave it a 3,\nchanged it to a 4,\nand the change wasn't reflected on the outside\n(<code>a<\/code> is still 3).<\/p>\n<p>But, in fact, Python is not <em>copying<\/em> the data into the function.<\/p>\n<p>To prove this, I'll show you a different function:<\/p>\n<pre><code class=\"language-py\">def clearly_not_pass_by_value(my_list):\n    my_list[0] = 42\n\nl = [1, 2, 3]\nclearly_not_pass_by_value(l)\nprint(l)\n## [42, 2, 3]<\/code><\/pre>\n<p>As we can see, the list <code>l<\/code>, that was defined outside of the function,\nchanged after calling the function <code>clearly_not_pass_by_value<\/code>.\nHence, Python does not use a pass-by-value model.<\/p>\n<h2 id=\"is-python-pass-by-reference\">Is Python pass-by-reference?<a href=\"#is-python-pass-by-reference\" class=\"toc-anchor after\" data-anchor-icon=\"#\" aria-label=\"Anchor\"><\/a><\/h2>\n<p>In a true pass-by-reference model,\nthe called function gets access to the variables of the callee!\nSometimes, it can <em>look<\/em> like that's what Python does,\nbut Python does not use the pass-by-reference model.<\/p>\n<p>I'll do my best to explain why that's not what Python does:<\/p>\n<pre><code class=\"language-py\">def not_pass_by_reference(my_list):\n    my_list = [42, 73, 0]\n\nl = [1, 2, 3]\nnot_pass_by_reference(l)\nprint(l)\n## [1, 2, 3]<\/code><\/pre>\n<p>If Python used a pass-by-reference model,\nthe function would've managed to completely change the value of <code>l<\/code>\noutside the function, but that's not what happened, as we can see.<\/p>\n<p>Let me show you an actual pass-by-reference situation.<\/p>\n<p>Here's some Pascal code:<\/p>\n<pre><code class=\"language-pas\">program callByReference;\nvar\n    x: integer;...<\/code><\/pre>","summary":"This article explains why Python doesn&#039;t use a pass-by-value system, nor a pass-by-reference.","date_modified":"2025-11-14T12:33:53+01:00","tags":["programming","python"],"image":"\/user\/pages\/02.blog\/02.pydonts\/pass-by-value-reference-and-assignment\/thumbnail.webp"},{"title":"Conditional expressions | Pydon&#039;t \ud83d\udc0d","date_published":"2021-09-28T00:00:00+02:00","id":"https:\/\/mathspp.com\/blog\/pydonts\/conditional-expressions","url":"https:\/\/mathspp.com\/blog\/pydonts\/conditional-expressions","content_html":"<p>This Pydon't will teach you how to use Python's conditional expressions.<\/p>\n\n<script async src=\"https:\/\/platform.twitter.com\/widgets.js\" charset=\"utf-8\"><\/script><p>(If you are new here and have no idea what a Pydon't is, you may want to read the\n<a href=\"\/blog\/pydonts\/pydont-manifesto\">Pydon't Manifesto<\/a>.)<\/p>\n<h2 id=\"introduction\">Introduction<a href=\"#introduction\" class=\"toc-anchor after\" data-anchor-icon=\"#\" aria-label=\"Anchor\"><\/a><\/h2>\n<p>Conditional expressions are what Python has closest to what is called a &ldquo;ternary operator&rdquo; in other languages.<\/p>\n<p>In this Pydon't, you will:<\/p>\n<ul><li>learn about the syntax of conditional expressions;<\/li>\n<li>understand the rationale behind conditional expressions;<\/li>\n<li>learn about the precedence of conditional expressions;<\/li>\n<li>see how to nest conditional expressions;<\/li>\n<li>understand the relationship between <code>if: ... elif: ... else:<\/code> statements and conditional expressions;<\/li>\n<li>see good and bad example usages of conditional expressions;<\/li>\n<\/ul><!--v--><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=\"what-is-a-conditional-expression\">What is a conditional expression?<a href=\"#what-is-a-conditional-expression\" class=\"toc-anchor after\" data-anchor-icon=\"#\" aria-label=\"Anchor\"><\/a><\/h2>\n<p>A conditional expression in Python is an expression\n(in other words, a piece of code that evaluates to a result)\nwhose value depends on a condition.<\/p>\n<h3 id=\"expressions-and-statements\">Expressions and statements<a href=\"#expressions-and-statements\" class=\"toc-anchor after\" data-anchor-icon=\"#\" aria-label=\"Anchor\"><\/a><\/h3>\n<p>To make it clearer, here is an example of a Python expression:<\/p>\n<pre><code class=\"language-py\">&gt;&gt;&gt; 3 + 4 * 5\n23<\/code><\/pre>\n<p>The code <code>3 + 4 * 5<\/code> is an expression, and that expression evaluates to 23.<\/p>\n<p>Some pieces of code are not expressions.\nFor example, <code>pass<\/code> is not an expression because it does not evaluate to a result.\n<code>pass<\/code> is just a statement, it does not &ldquo;have&rdquo; or &ldquo;evaluate to&rdquo; any result.<\/p>\n<p>This might be odd (or not!) but to help you figure out if something is an expression or not,\ntry sticking it inside a <code>print<\/code> function.\nExpressions can be used inside other expressions, and function calls are expressions.\nTherefore, if it can go inside a <code>print<\/code> call, it is an expression:<\/p>\n<pre><code class=\"language-py\">&gt;&gt;&gt; print(3 + 4 * 5)\n23<\/code><\/pre>\n<p>As another example, the keyword <code>pass<\/code> defines a statement and therefore cannot be used inside <code>print<\/code>:<\/p>\n<pre><code class=\"language-py\">&gt;&gt;&gt; print(pass)\n  File \"&lt;stdin&gt;\", line 1\n    print(pass)\n          ^\nSyntaxError: invalid syntax<\/code><\/pre>\n<h3 id=\"conditions\">Conditions<a href=\"#conditions\" class=\"toc-anchor after\" data-anchor-icon=\"#\" aria-label=\"Anchor\"><\/a><\/h3>\n<p>We are very used to using <code>if<\/code> statements to run pieces of code when certain <em>conditions<\/em> are met.\nRewording that, a condition can dictate what piece(s) of code run.<\/p>\n<p>In conditional expressions, we will use a condition to change the value to which the expression evaluates.<\/p>\n<p>Wait, isn't this the same as an <code>if<\/code> statement?\nNo!\nStatements and expressions are <em>not<\/em> the same thing.<\/p>\n<h3 id=\"syntax\">Syntax<a href=\"#syntax\" class=\"toc-anchor after\" data-anchor-icon=\"#\" aria-label=\"Anchor\"><\/a><\/h3>\n<p>Instead of beating around the bush, let me just show you the anatomy of a conditional expression:<\/p>\n<pre><code class=\"language-py\">expr_if_true if condition else expr_if_false<\/code><\/pre>\n<p>A conditional expression is composed of three sub-expressions and the keywords <code>if<\/code> and <code>else<\/code>.\nNone of these components are optional.\nAll of them have to be present.<\/p>\n<p>How does this work?<\/p>\n<p>First, <code>condition<\/code> is evaluated.\nThen, depending on whether <code>condition<\/code> evaluates to <a href=\"\/blog\/pydonts\/truthy-falsy-and-bool\">Truthy or Falsy<\/a>,\nthe expression evaluates <code>expr_if_true<\/code> or <code>expr_if_false<\/code>, respectively.<\/p>\n<p>As you may be guessing from the names,\n<code>expr_if_true<\/code> and <code>expr_if_false<\/code> can themselves be expressions.\nThis means they can be simple literal values like <code>42<\/code> or <code>\"spam\"<\/code>,\nor other &ldquo;complicated&rdquo; expressions....<\/p>","summary":"This Pydon&#039;t will teach you how to use Python&#039;s conditional expressions.","date_modified":"2025-11-14T12:33:53+01:00","tags":["programming","python"],"image":"\/user\/pages\/02.blog\/02.pydonts\/conditional-expressions\/thumbnail.webp"}]}
