<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Assertion | Haobin Tan</title><link>https://haobin-tan.netlify.app/tags/assertion/</link><atom:link href="https://haobin-tan.netlify.app/tags/assertion/index.xml" rel="self" type="application/rss+xml"/><description>Assertion</description><generator>Hugo Blox Builder (https://hugoblox.com)</generator><language>en-us</language><lastBuildDate>Sat, 03 Dec 2022 00:00:00 +0000</lastBuildDate><image><url>https://haobin-tan.netlify.app/media/icon_hu7d15bc7db65c8eaf7a4f66f5447d0b42_15095_512x512_fill_lanczos_center_3.png</url><title>Assertion</title><link>https://haobin-tan.netlify.app/tags/assertion/</link></image><item><title>Assertion</title><link>https://haobin-tan.netlify.app/docs/coding/python/py-basics/assertion/</link><pubDate>Sat, 03 Dec 2022 00:00:00 +0000</pubDate><guid>https://haobin-tan.netlify.app/docs/coding/python/py-basics/assertion/</guid><description>&lt;ul>
&lt;li>The proper use of assertions is to &lt;strong>inform developers about &lt;em>unrecoverable&lt;/em> errors in a program.&lt;/strong>&lt;/li>
&lt;li>Assertions are &lt;em>not&lt;/em> intended to signal expected error conditions.&lt;/li>
&lt;li>Assertions are meant to be &lt;em>internal self-checks&lt;/em> for your program.&lt;/li>
&lt;/ul>
&lt;p>keep in mind that Python’s assert statement is a debugging aid, not a mechanism for handling run-time errors.&lt;/p>
&lt;p>The goal of using assertions is to let developers find the likely root cause of a bug more quickly. An assertion error should &lt;em>NEVER&lt;/em> be raised unless there’s a bug in your program.&lt;/p>
&lt;h2 id="syntax">Syntax&lt;/h2>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="n">assert_stmt&lt;/span> &lt;span class="p">:&lt;/span>&lt;span class="o">:=&lt;/span> &lt;span class="s2">&amp;#34;assert&amp;#34;&lt;/span> &lt;span class="n">expression1&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="s2">&amp;#34;,&amp;#34;&lt;/span> &lt;span class="n">expression2&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;ul>
&lt;li>&lt;code>expression1&lt;/code> is the condition we test&lt;/li>
&lt;li>the optional &lt;code>expression2&lt;/code> is an error message that’s displayed if the assertion fails.&lt;/li>
&lt;/ul>
&lt;p>At execution time, the Python interpreter transforms each assert state- ment into roughly the following sequence of statements:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="k">if&lt;/span> &lt;span class="n">__debug__&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="ow">not&lt;/span> &lt;span class="n">expression1&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">raise&lt;/span> &lt;span class="ne">AssertionError&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">expression2&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Before the assert condition is checked, there’s an additional check for the &lt;code>__debug__&lt;/code> global variable. It’s a built-in boolean flag that’s true under normal circumstances and false if optimizations are requested.&lt;/p>
&lt;h2 id="two-caveats-when-using-asserts">Two caveats when using asserts&lt;/h2>
&lt;h3 id="dont-use-asserts-for-data-validation">Don’t Use Asserts for Data Validation&lt;/h3>
&lt;p>Assertions can be globally disabled3 with the &lt;code>-0&lt;/code> and &lt;code>-00&lt;/code> command line switches, as well as the &lt;code>PYTHONOPTIMIZE&lt;/code> environment variable in CPython!&lt;/p>
&lt;p>$\rightarrow$ This turns any assert statement into a null-operation: the assertions simply get compiled away and won’t be evaluated 🤪, which means that none of the conditional expressions will be executed. As a side-effect, it becomes extremely dan- gerous to use assert statements as a quick and easy way to validate input data.&lt;/p>
&lt;p>The solution to avoid this problem is: &lt;strong>NEVER use assertions to do data validation.&lt;/strong> Instead, we could do our validation with regular &lt;code>if&lt;/code>-statements and raise validation exceptions if necessary&lt;/p>
&lt;h4 id="example">Example&lt;/h4>
&lt;p>❌ Don&amp;rsquo;t do&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">delete_product&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">prod_id&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">user&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">assert&lt;/span> &lt;span class="n">user&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">is_admin&lt;/span>&lt;span class="p">(),&lt;/span> &lt;span class="s1">&amp;#39;Must be admin&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">assert&lt;/span> &lt;span class="n">store&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">has_product&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">prod_id&lt;/span>&lt;span class="p">),&lt;/span> &lt;span class="s1">&amp;#39;Unknown product&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">store&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">get_product&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">prod_id&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">delete&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>✅ Do&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">delete_product&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">product_id&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">user&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="ow">not&lt;/span> &lt;span class="n">user&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">is_admin&lt;/span>&lt;span class="p">():&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">raise&lt;/span> &lt;span class="n">AuthError&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;Must be admin to delete&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="ow">not&lt;/span> &lt;span class="n">store&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">has_product&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">product_id&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">raise&lt;/span> &lt;span class="ne">ValueError&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;Unknown product id&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">store&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">get_product&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">product_id&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">delete&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="asserts-that-never-fail">Asserts That Never Fail&lt;/h3>
&lt;p>When you &lt;strong>pass a tuple as the first argument&lt;/strong> in an &lt;code>assert&lt;/code> statement, the assertion always evaluates as &lt;code>true&lt;/code> and therefore never fails.&lt;/p>
&lt;p>For example, the following assertion will never fail:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="k">assert&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">1&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="mi">2&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;This should fail&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Reason is that non-empty tuples is always &lt;code>true&lt;/code> in Python.&lt;/p>
&lt;p>A good countermeasure you can apply to prevent this syntax quirk from causing trouble is to use a code linter. Newer versions of Python 3 will also show a syntax warning for these dubious asserts.&lt;/p></description></item></channel></rss>