www

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs

index.html (5914B)


      1 <!DOCTYPE html>
      2 <html>
      3 	<head>
      4 		<title>banna - ramblings</title>
      5 		<meta name="viewport" content="width=device-width, initial-scale=1">
      6 		<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
      7 		<link rel="stylesheet" href="/styles/style.css" />
      8 		<link rel="stylesheet" href="/styles/look.css" />
      9 		<link rel="stylesheet" href="/styles/codetheme.css" />
     10 		<script src="/scripts/highlight.js"></script>
     11 		<script>hljs.initHighlightingOnLoad();</script>
     12 	</head>
     13 
     14 	<body>
     15 		<div id="sidebar">
     16 			<div id="logo">
     17 				<a href="/">
     18 					<img src="/banna.png" alt="banna.tech" height="45" width="201" />
     19 				</a>
     20 			</div>
     21 			<div id="nav">
     22 				<a class="current" href="/post">blog</a>
     23 				<a class="" href="/things">things</a>
     24 				<a class="" href="/about">about</a>
     25 			</div>
     26 		</div>
     27 
     28 		<div id="wrapper">
     29 			<div id="content">
     30 <div class="post">
     31     <a href="/post/chained_conditional_expressions_in_python" class="link"><h1 class="header">Chained conditional expressions in python</h1></a>
     32     <span class="date">Posted on July, 12 2015</span>
     33     <div class="content">
     34 <blockquote>
     35 <p>NOTE: Before you start reading this, read up on <a href="https://en.wikipedia.org/wiki/Stack_machine">stack machines</a> if you have not done so yet. In this post I'll be going over some python bytecode, knowing what a stack machine will help a lot!</p>
     36 </blockquote>
     37 <pre><code>False == False in [False]
     38 </code></pre>
     39 <p>A friend had recently showed this statement to me, and asked what it evaluates 
     40 to. I replied 'False', of course, since <code>False == False</code> is <code>True</code>, and <code>True</code> 
     41 is not in the list <code>[False]</code>. Until, of course, I threw it in the python 
     42 interpreter.</p>
     43 <pre><code>&gt;&gt;&gt; False == False in [False]
     44 True
     45 </code></pre>
     46 <p>Now, now... what's this madness? Is python pulling a javascript? To answer this
     47 problem we will disassemble a python function into python bytecode and evaluate
     48 it line-by-line.</p>
     49 <pre><code>&gt;&gt;&gt; def func():
     50 ...     # We'll name these constants as they pop up in the stack
     51 ...     #      A        B        C
     52 ...     return False == False in [False]
     53 ... 
     54 &gt;&gt;&gt; import dis
     55 &gt;&gt;&gt; dis.dis(func)
     56   2           0 LOAD_GLOBAL              0 (False)
     57               3 LOAD_GLOBAL              0 (False)
     58               6 DUP_TOP             
     59               7 ROT_THREE           
     60               8 COMPARE_OP               2 (==)
     61              11 JUMP_IF_FALSE_OR_POP    24
     62              14 LOAD_GLOBAL              0 (False)
     63              17 BUILD_LIST               1
     64              20 COMPARE_OP               6 (in)
     65              23 RETURN_VALUE        
     66         &gt;&gt;   24 ROT_TWO             
     67              25 POP_TOP             
     68              26 RETURN_VALUE
     69 </code></pre>
     70 <h3>Lines 0-3</h3>
     71 <p>On lines 0-3, <code>LOAD_GLOBAL</code> is called twice to load <code>A</code> and <code>B</code> into the stack. Below is a representation of the stack, with the label/ID mnemonic above each stack element. </p>
     72 <pre><code>#        TOS (top-of-stack), TOS1
     73 #        B                   A
     74 stack = [False,              False]
     75 </code></pre>
     76 <h3>Line 6</h3>
     77 <p><code>DUP_TOP</code> duplicates the 'top' of the stack.</p>
     78 <pre><code>#        TOS  , TOS1
     79 #        DUP.B  B      A
     80 stack = [False, False, False]
     81 </code></pre>
     82 <h3>Line 7</h3>
     83 <p><code>ROT_THREE</code> rotates the top three elements in the stack.</p>
     84 <pre><code>#        TOS  , TOS1
     85 #        B      A      DUP.B
     86 stack = [False, False, False]
     87 </code></pre>
     88 <h3>Line 8</h3>
     89 <p>The next instruction is <code>COMPARE_OP(==)</code>, which compares if <code>TOS == TOS1</code>,
     90 pops <code>TOS</code> and <code>TOS1</code> before pushing the result of <code>TOS == TOS1</code>.</p>
     91 <pre><code>#        TOS , TOS1
     92 #        A==B, DUP.B
     93 stack = [True, False]
     94 </code></pre>
     95 <h3>Line 11</h3>
     96 <p><code>JUMP_IF_FALSE_OR_POP</code> jumps if <code>TOS == False</code>, else it pops the stack and moves
     97 on</p>
     98 <pre><code>#        TOS
     99 #        DUP.B
    100 stack = [False]
    101 </code></pre>
    102 <p>Huh, won't you look at that? The result of <code>False == False</code> was thrown away
    103 completely, leaving only the duplicate of B in the stack. This tells me that my 
    104 initial theory was completely wrong, python is not chaining these operations
    105 together at all!</p>
    106 <h3>Lines 14-17</h3>
    107 <p>Now, the next set of instructions (14-17) builds the list, by pushing <code>False</code> on
    108 the stack and using <code>BUILD_LIST(size)</code> to create the list.</p>
    109 <pre><code>#       TOS  , TOS1
    110 #        C     B
    111 stack = [List, False]
    112 </code></pre>
    113 <h3>Line 20</h3>
    114 <p><code>COMPARE_OP(in)</code> tests whether <code>TOS1</code> is in list <code>TOS</code>, which is <code>True</code>.</p>
    115 <pre><code>#        TOS
    116 stack = [True]
    117 </code></pre>
    118 <p>The line after that is <code>RETURN_VALUE</code>, which returns the value of <code>TOS</code>, which
    119 is what we get when we run func()</p>
    120 <h2>Analysis</h2>
    121 <p>From what we can see, python does not chain these operations together as
    122 expected. It actually doesn't chain the operations together at all.</p>
    123 <p>Looking at what values are in the stack at each instruction, we can see that
    124 instead of keeping the result of <code>A == B</code>, it keeps what we named as <code>B</code>
    125 in the stack and tested whether or not <code>B</code> was in the list <code>C</code>. On line 11,
    126 <code>JUMP_IF_FALSE_OR_POP</code> was used. If <code>A == B</code> were to evaluate to <code>False</code>
    127 , it would end up jumping to line <code>24</code> and return <code>False</code>.</p>
    128 <h2>Conclusion</h2>
    129 <p>In short, what the bytecode tells us is that the statement we wrote as</p>
    130 <p><code>A == B in [C]</code> is interpreted as <code>A == B and B in C</code>.</p>
    131 <p>This must mean that given a statement structure as <code>A is B is C</code>, the statement
    132 is expanded into <code>A is B and B is C</code>.</p>
    133     </div>
    134 </div>
    135 
    136 
    137 			</div>
    138 		</div>
    139 	</body>
    140 </html>