You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

446 lines
22 KiB

<!doctype html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>My Learning Website</title>
<link href="/styles/styles.css" rel="stylesheet" type="text/css">
<link href="/programming/styles/styles.css" rel="stylesheet" type="text/css">
<!-- HTML5 shim and Respond.js for IE8 support of HTML5 elements and media queries -->
<!-- WARNING: Respond.js doesn't work if you view the page via file:// -->
<!--[if lt IE 9]>
<script src="https://oss.maxcdn.com/html5shiv/3.7.2/html5shiv.min.js"></script>
<script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
<![endif]-->
</head>
<body>
<div class="banner">
<h1 class="courselink">Python Essential Training</h1>
<h2 class="lecturer">LinkedIn Learning : Bill Weinman</h2>
<h2 class="episodetitle">Operators</h2>
</div>
<article>
<h2 class="sectiontitle">Arithmetic Operators</h2>
<table>
<tr>
<th>Operator</th>
<th>Operation</th>
</tr>
<tr>
<td>+</td>
<td>Addition</td>
</tr>
<tr>
<td>-</td>
<td>Subtraction</td>
</tr>
<tr>
<td>*</td>
<td>Multiplication</td>
</tr>
<tr>
<td>/</td>
<td>Division</td>
</tr>
<tr>
<td>//</td>
<td>Integer Division</td>
</tr>
<tr>
<td>%</td>
<td>Modulo</td>
</tr>
<tr>
<td>**</td>
<td>Exponent</td>
</tr>
<tr>
<td>-</td>
<td>Unary negative</td>
</tr>
<tr>
<td>+</td>
<td>Unary positive</td>
</tr>
</table>
<h2 class="sectiontitle">Bitwise Operators</h2>
<table>
<tr>
<th>Operator</th>
<th>Operation</th>
</tr>
<tr>
<td>&amp;</td>
<td>And</td>
</tr>
<tr>
<td>|</td>
<td>Or</td>
</tr>
<tr>
<td>^</td>
<td>Xor</td>
</tr>
<tr>
<td>&lt;&lt;</td>
<td>Shift left</td>
</tr>
<tr>
<td>&rt;&rt;</td>
<td>Shift right</td>
</tr>
</table>
<p>Note that to keep things clear, I will refer to bits according to their position and starting from the least significant bit so for example if we have a 2 bit binary number, 01, the 1 is bit zero and the zero is bit 1.</p>
<p>Let's look at an example.</p>
<pre class="inset">
x = 0x0a
y = 0x02
z = x &amp; y
print(f'(hex) x is {x:02x}, y is {y:02x}, z is {z:02x}')
print(f'(bin) x is {x:08b}, y is {y:08b}, z is {z:08b}')</pre>
<p>The output from this is.</p>
<pre class="inset">
(hex) x is 0a, y is 02, z is 02
(bin) x is 00001010, y is 00000010, z is 00000010</pre>
<p>The first two lines are creating hexadecimal numbers to initialise x and y and we then perform a bitwise and on the two numbers and store the result in z. We then output all three numbers in hex format and then binary. Note that the 02 in the first print statement (for example, {y:02x}) looks suspiciously like the value of both y and z but that's coincidental. The y is the variable name, the colon introduces a modifier and the 02 specifies 2 leading zeroes. This means that enough zeroes will be added to the start of the number to be able to express it with 2 digits. The x indicates that this is a hex number.</p>
<p>We can see something similar in the second print statement (for example {x:08b}) which is similar but because it is an 8 bit binary number, we want to add enough leading zeroes to give us an 8 digit number and the b indicates that the number is binary.</p>
<p>The bitwise and operator compares each corresponding bit in the two operands and the corresponding bit in the result will be 1 in the result if the bit is set in both of the operands. In our example, all the bits in x are set to zero except bit 1 and bit 3 and all of the bits in y are set to 0 except bit 1. Since the only bit that is set (that is, has a value of 1) in both operands is bit 1, bit 1 is the only bit that will be set in thee result and so z (the result) is 0000 0010. This would probably be clearer if you compare the two numbers in their binary form.</p>
<pre class="inset-binary">
x 0000 1010
y 0000 0010
-------------------------
z 0000 0010</pre>
<p>This is just straightforward Boolean logic and it is very common. The bitwise and is commonly used as a mask such as a network subnet mask. As an example, lets say that you have a subnet mask of 255.255.255.0, so that's 4 8-bit numbers, in the first 3, all 8 bits are 1, in the fourth, all 8 bits are 0.</p>
<p>If you take an ip address, let's say 192.168.0.13, we can use the subnet mask to get the network part of the address from this ip address, the network address in this case being 192.168.0.0.</p>
<p>If we take the first byte from each of these, so 255 from the mask and 192 from the ip address. If we compare each bit in turn from bit 0 to bit 7, the result will be 1 if both bit 0 in the mask and bit 0 in the ip address are set to 1. Since all the bits in the mask are set to 1, this means that the result will be the same as the bit in the ip address. This applies for each of the 8 bits and the overall results is that we get the number from the ip address.</p>
<p>In other words, if we perform a bitwise and on 2 8-bit numbers, let's say a and b and 8 has a value of 255, the result, let's call that c, will be the same as b.</p>
<p>On the other hand, if a has a value of 0 (all 8 bits are set to zero), it doesn't matter what the bit is set to (0 or 1) in b, the result will always be 0 in the corresponding bit in the result. When we perform this operation with our subnet mask of 255.255.255.0 and our ip address of 192.168.0.13, the result will be 192.168.0.0 (the network address). What we are actually doing here is masking part of the address, the last byte. Setting this value to 0 whilst leaving the other bytes unchanged gives us the network address.</p>
<p>Another common use of bitwise and is to determine whether a specific bit is set in a byte. For example, let's say that we want to find out whether bit 4 is set in a particular number, let's say 164. An 8 bit number where only bit 4 is set has a value, in decimal of 16. If we perform a bitwise and on 164 and 16, there are two possible results. If bit 4 is set in 164, the result will be 16. If not, the result will be 0. If we have some code that we want to run if the bit is set, we can use this as the condition in an if statement like this.</p>
<pre class="inset">
x = 164
y = 16
if (x &amp; y):
print('In byte x, bit 4 is set')
else:
print('In byte x, bit 4 is not set')
print(f'(bin) x is {x:08b}, y is {y:08b}')</pre>
<p>The output we get from this is</p>
<pre class="inset">
In byte x, bit 4 is not set
(bin) x is 10100100, y is 00010000</pre>
<p>In this case, we can see that bit 4 is not set in x and we can see that confirmed in the binary number displayed in the output. This code works because if the bit is set, x &amp; y is going to return a non-zero value which evaluates to true and the code block attached to the if statement will run. If it is not set (as was the case in our example), x &amp; y will return 0 and the code in the else clause will run.</p>
<p>You can run this example using different values for x and you should find about 50% of numbers selected at random will have the bit set (of all the possible values an 8 bit number can hold, exactly 50% of these will have bit 4 set and 50% will have bit 4 not set). As an example, if you give x a value of 200, you will see that bit 4 is set there.</p>
<p>The principle is the same when using bitwise <em>or</em> and bitwise <em>xor</em> except, of course, that we are comparing corresponding bits with <em>or</em> which means that the bit is set in the result if it is set in either of the operands or <em>xor</em> which means that the bit is set in the result if it is set in either of the operands but not in both.</p>
<p>At first glance, it may not be obvious what shift left and shift right do. To illustrate this, consider the following example.</p>
<pre class="inset">
x = 1
y = x &lt;&lt; 1
print(f'(bin) x is {x:08b}, y is {y:08b}')
y = y &lt;&lt; 1
print(f'(bin) x is {x:08b}, y is {y:08b}')
y = y &lt;&lt; 1
print(f'(bin) x is {x:08b}, y is {y:08b}')
y = y &lt;&lt; 1
print(f'(bin) x is {x:08b}, y is {y:08b}')
y = y &lt;&lt; 1
print(f'(bin) x is {x:08b}, y is {y:08b}')
y = y &lt;&lt; 1
print(f'(bin) x is {x:08b}, y is {y:08b}')
y = y &lt;&lt; 1
print(f'(bin) x is {x:08b}, y is {y:08b}')
y = y &lt;&lt; 1
print(f'(bin) x is {x:08b}, y is {y:08b}')</pre>
<p>We have a number to start with which is x and this has a value of 1 so in binary terms, this means that bit 0 is set to 1 and all the other bits are set to 0. Shift left, effectively moves the set bit to the left (by one place in our example) so when we set y to the value of x shifted left by 1, in y, bit 1 is et to 1 and all other bits are set to 0. The output from this code is shown below and this shows the bit being shifted every time.</p>
<pre class="inset">
(bin) x is 00000001, y is 00000010
(bin) x is 00000001, y is 00000100
(bin) x is 00000001, y is 00001000
(bin) x is 00000001, y is 00010000
(bin) x is 00000001, y is 00100000
(bin) x is 00000001, y is 01000000
(bin) x is 00000001, y is 10000000
(bin) x is 00000001, y is 100000000</pre>
<p>Notice that we are displaying 8 bits but in the last line of the output, shifting the set bit moves it over to bit 8 so we now have a 9 bit number and if we continued to shift it, the number would continue to grow. I have amended the previous code example to allow further experimentation with shift left.</p>
<pre class="inset">
x = 1
step = 1
y = x &lt;&lt; step
print(f'(bin) x is {x:08b}, y is {y:08b}')
y = y &lt;&lt; step
print(f'(bin) x is {x:08b}, y is {y:08b}')
y = y &lt;&lt; step
print(f'(bin) x is {x:08b}, y is {y:08b}')
y = y &lt;&lt; step
print(f'(bin) x is {x:08b}, y is {y:08b}')
y = y &lt;&lt; step
print(f'(bin) x is {x:08b}, y is {y:08b}')
y = y &lt;&lt; step
print(f'(bin) x is {x:08b}, y is {y:08b}')
y = y &lt;&lt; step
print(f'(bin) x is {x:08b}, y is {y:08b}')
y = y &lt;&lt; step
print(f'(bin) x is {x:08b}, y is {y:08b}')</pre>
<p>This allows us to set any value for x and for step which is the number of bits by which we are shifting left each time. With a little bit of experimentation, we can see that if there are multiple bits set, they will all be shifted at the same time. You might expect that there is a limit to the number of times you can shift a bit to the left. For instance, a Python int is 32 bits long, so you might expect the number to become 0 (in effect, because the bit that has been set is shifted so far to the left that it is moved off the number) or that the number wraps around back to bit 0.</p>
<p>Let's change things around a bit with the following code example, which may give a clearer idea of what happens when we run out of bits!</p>
<pre class="inset">
x = 256
step = 1
y = x &gt;&gt; step
print(f'(bin) x is {x:08b}, y is {y:08b}')
y = y &gt;&gt; step
print(f'(bin) x is {x:08b}, y is {y:08b}')
y = y &gt;&gt; step
print(f'(bin) x is {x:08b}, y is {y:08b}')
y = y &gt;&gt; step
print(f'(bin) x is {x:08b}, y is {y:08b}')
y = y &gt;&gt; step
print(f'(bin) x is {x:08b}, y is {y:08b}')
y = y &gt;&gt; step
print(f'(bin) x is {x:08b}, y is {y:08b}')
y = y &gt;&gt; step
print(f'(bin) x is {x:08b}, y is {y:08b}')
y = y &gt;&gt; step
print(f'(bin) x is {x:08b}, y is {y:08b}')
y = y &gt;&gt; step
print(f'(bin) x is {x:08b}, y is {y:08b}')</pre>
<p>This time, we are starting with a number with only bit 8 set to 1. Note that we are shifting right in this example and we are shifting before displaying the number for the first time so the first time we see it displayed, only bit 7 is set. We then shift right a further 8 times, displaying the result each time. The second last shift gives a result of 1 (so only bit 0 is set) and when we perform one more shift right operation, the result becomes zero so we can see that when there is nowhere else to shift the bit to, it just disappears, it doesn't wrap around.</p>
<p>There is no obvious use for a bitwise shift that I am aware of but one possible use is that if a number is a power of two, shifting left will double the number and shifting it right will halve it. For more information, it is probably worth checking out the Python online docs for both <a href="https://python-reference.readthedocs.io/en/latest/docs/operators/bitwise_left_shift.html">shift left</a> and <a href="https://python-reference.readthedocs.io/en/latest/docs/operators/bitwise_right_shift.html">shift right</a>.</p>
<h2 class="sectiontitle">Comparison Operators</h2>
<table>
<tr>
<th>Operator</th>
<th>Operation</th>
</tr>
<tr>
<td>&lt;</td>
<td>Less than</td>
</tr>
<tr>
<td>&gt;</td>
<td>Greater than</td>
</tr>
<tr>
<td>&lt;=</td>
<td>Less than or equal to</td>
</tr>
<tr>
<td>&gt;=</td>
<td>Greater than or equal to</td>
</tr>
<tr>
<td>==</td>
<td>Equal to</td>
</tr>
<tr>
<td>!=</td>
<td>Not equal to</td>
</tr>
</table>
<p>These work in exactly the same way as they do in other languages such as C or Perl. As in these other languages, a single equals sign is used as the assignment operator, not as a comparison operator. Consider the following snippet of code.</p>
<pre class="inset">
a = 6
if (a = 5):
print('a is 5')</pre>
<p>In some programming languages, this would be allowed, but would output the result that a is 5. This is because in the conditional statement, there is no comparison operator. What this is doing is setting the value of a to 5 and this would normally return a true value. In Python, this syntax is not allowed so if you try to use an assignment statement in a conditional, you will get an invalid syntax error.</p>
<p>Let's look at another example that tells us a little bit more about the assignment operator. Look it over and see if you can determine what the output is going to be.</p>
<pre class="inset">
x = { 'Geddy Lee':2112, 'Geoff Hurst':1966, 'Ferenc Puskas':1954, 'Steve Gerrard':2005, 'Mo Salah':2020, 'Virgil Van Dijk':2019, 'John Lennon': 1962}
y = { 'Geddy Lee':2112, 'Geoff Hurst':1966, 'Ferenc Puskas':1954, 'Steve Gerrard':2005, 'Mo Salah':2020, 'Virgil Van Dijk':2019, 'John Lennon': 1962}
if x == y:
print('x and y are the same list')
else:
print('x and y are identical but not the same list')</pre>
<p>There are two possibilities, either x and y will be the same because they both have the same values or they will be different because they have the same values but have different object ids. When we run this, we see the message that both x and y are the same and we can add a couple of lines to output the ids so that we can confirm that they have different ids. From this, we can tell that the comparison operator, ==, is comparing values so two variables will be the same if they have the same value, they don't have to be the same object.</p>
<p>You may be aware of the fact that in some programming languages, === is used as a comparison operator. In general, it is used as a strict comparison operator, for example, in JavaScript, the operands must have the same data type as well as the same value so return a true value and in Java, you will only get a true value if both of the operands reference the same object. However, this is not used in Python.</p>
<p>In Python, however, you can use the <em>is</em> operator which does the same thing so if we change our condition to</p>
<pre class="inset">
if x is y:</pre>
<p>when we run this, the output is</p>
<pre class="inset">
x and y are identical but not the same list
1973246927616
1973246927808</pre>
<p>We can also change the line initialising y to</p>
<pre class="inset">
y= x</pre>
<p>This causes y to reference the same object that x is referencing, so if we run the code again, the output becomes</p>
<pre class="inset">
x and y are the same list
1909997544192
1909997544192</pre>
<p>From this, we can see that a true value has been returned since x and y reference the same object and this is confirmed by the fact that both x and y have the same id.</p>
<h2 class="sectiontitle">Boolean Operators</h2>
<table>
<tr>
<th>Operator</th>
<th>Returns true if</th>
</tr>
<tr>
<td>and</td>
<td>Both operands are true</td>
</tr>
<tr>
<td>or</td>
<td>At least one operand is true</td>
</tr>
<tr>
<td>not</td>
<td>The operand is false</td>
</tr>
<tr>
<td>in</td>
<td>The given element is in a given set</td>
</tr>
<tr>
<td>not in</td>
<td>The given element is not in a given set</td>
</tr>
<tr>
<td>is</td>
<td>Both operands reference the same object (have the same id)</td>
</tr>
<tr>
<td>is not</td>
<td>Both operands reference different objects (do not have the same id)</td>
</tr>
</table>
<p>In the table shown above, several references are made to an operand is true or we might say, returns a true value or evaluates to true. This is something we have mentioned in previous chapters so just as a quick recap, let's look at some of the things that can return a true value. Let's assume that we have a snippet of code as follows.</p>
<pre class="inset">
if condition:
print('True')
else:
print('False')</pre>
<p>The question then becomes, what sort of things can we insert as the condition so that the output is 'True' and what sort of things would give the output as 'False'.</p>
<p>For these examples, assume that a = 7, b = 5, x is the tuple (3, 4, 5) and y is the list["HTML", "CSS", "JavaScript", "Python"].</p>
<table>
<tr>
<th>Type of condition</th>
<th>Evaluates to true</th>
<th>Evaluates to false</th>
</tr>
<tr>
<td>Comparison operator: &gt;</td>
<td>a &gt; b</td>
<td>b &gt; a</td>
</tr>
<tr>
<td>Comparison operator: &lt;=</td>
<td>5 &lt;= 5</td>
<td>7 &lt; 5</td>
</tr>
<tr>
<td>Comparison operator: ==</td>
<td>a == 7</td>
<td>a == b</td>
</tr>
<tr>
<td>Comparison operator: !=</td>
<td>a != b</td>
<td>a != 7</td>
</tr>
<tr>
<td>Logical operator: and</td>
<td>a and b</td>
<td>a and 0</td>
</tr>
<tr>
<td>Logical operator: or</td>
<td>a or b</td>
<td>a == 5 or b == 7</td>
</tr>
<tr>
<td>Logical operator: not</td>
<td>a == b</td>
<td>a == 7</td>
</tr>
<tr>
<td>Identity operator: is</td>
<td>a is 7</td>
<td>a is 5</td>
</tr>
<tr>
<td>Identity operator: is not</td>
<td>a is not 5</td>
<td>a is not 7</td>
</tr>
<tr>
<td>Membership operator (list element): is</td>
<td>y[3] = 'Python'</td>
<td>y[3] = 'PHP'</td>
</tr>
<tr>
<td>Membership operator (list element): is not</td>
<td>y[0] = 'Python'</td>
<td>y[0] = 'HTML'</td>
</tr>
<tr>
<td>Membership operator: in</td>
<td>b in x</td>
<td>a in x</td>
</tr>
<tr>
<td>Membership operator: not in</td>
<td>a not in x</td>
<td>b not in x</td>
</tr>
<tr>
<td>Simple condition: integer</td>
<td>a</td>
<td>0</td>
</tr>
<tr>
<td>Simple condition: string</td>
<td>"Hello World"</td>
<td>""</td>
</tr>
<tr>
<td>Simple condition: bool</td>
<td>True</td>
<td>False</td>
</tr>
</table>
<p>This isn't intended to be an exhaustive list, but it should provide a useful summary of some of the concepts we have seen in relation to conditionals and various types of operators that can be used in a conditional statement. This can also be a useful way of testing whether a condition gives you the results you expect because you can simply insert the condition you want to test, adding additional variables if needed, and the code will tell you whether the conditional will return a true or a false result.</p>
<h2 class="sectiontitle">Operator Precedence</h2>
<p>Operator precedence is important in Python, just as it is in any programming language because it ensures that calculations are performed in the way that you except. As an example, let's say that you have an arithmetic operation like this.</p>
<pre class="inset">
x = 5 + 2 * 7</pre>
<p>If we assume that the operations are performed from left to right, you 5 + 2 = 7 and then multiply that by 7 to get 49. In arithmetic, it is normal for multiplication to come first and if we perform the calculation that way, we get 2 * 7 = 14 and we then add 5 to that to get 19.</p>
<p>Neither of these answers are definitively correct, but there is one correct way that this will work in Python, so from that perspective there is a correct way and an incorrect way.</p>
<p>From a programmer's perspective, you need to think about what order you want to perform the operations in. The multiplication will always come before the addition, so if we want to do the addition first, we need to force the interpreter to give the addition a higher precedence by putting it in parentheses (which have a higher precedence than multiplication). To recap</p>
<pre class="inset">
x = 5 + 2 * 7</pre>
<p>will evaluate to 19 because the multiplication is performed first.</p>
<pre class="inset">
x = (5 + 2) * 7</pre>
<p>will evaluate to 49 because the operation in parentheses (is performed first). The Python documentation provides a full list detailing the <a href="https://docs.python.org/3/reference/expressions.html#operator-precedence">operator precedence</a>.</p>
</article>
<div class="btngroup">
<button class="button" onclick="window.location.href='conditionals.html';">
Previous Chapter - Conditionals
</button>
<button class="button" onclick="window.location.href='loops.html';">
Next Chapter - Loops
</button>
<button class="button" onclick="window.location.href='pythonessentialtraining.html'">
Course Contents
</button>
<button class="button" onclick="window.location.href='/programming/programming.html'">
Programming Page
</button>
<button class="button" onclick="window.location.href='/index.html'">
Home
</button>
</div>
</body>
3 months ago
</html>