Booleans: Boolean Operators - Lecture

Fred Baptiste
A free video tutorial from Fred Baptiste
Professional Developer and Mathematician
4.8 instructor rating • 4 courses • 37,622 students

Learn more from the full course

Python 3: Deep Dive (Part 1 - Functional)

Variables, Functions and Functional Programming, Closures, Decorators, Modules and Packages

44:37:26 of on-demand video • Updated August 2020

  • An in-depth look at variables, memory, namespaces and scopes
  • A deep dive into Python's memory management and optimizations
  • In-depth understanding and advanced usage of Python's numerical data types (Booleans, Integers, Floats, Decimals, Fractions, Complex Numbers)
  • Advanced Boolean expressions and operators
  • Advanced usage of callables including functions, lambdas and closures
  • Functional programming techniques such as map, reduce, filter, and partials
  • Create advanced decorators, including parametrized decorators, class decorators, and decorator classes
  • Advanced decorator applications such as memoization and single dispatch generic functions
  • Use and understand Python's complex Module and Package system
  • Idiomatic Python and best practices
  • Understand Python's compile-time and run-time and how this affects your code
  • Avoid common pitfalls
English [Auto] Hi. And this video, we're going to continue looking at boolean operators, but in a little bit more detail in particular, we're going to consider boolean operators in the context of truth values. So let's just bring back our regular truth table, we have these inputs for X and Y, and then we have the result of X and Y and X or Y. So normally boolean operators are defined to operate on boolean values and return boolean values. In fact, that's called a boolean algebra and and and or just operate in that boolean algebra. And that means that these operators are only defined for booleans and will always return a boolean. So for example, if we have true or false, that will return true. We could even use comparisons like this. So in this case, one equals two equals three, then A is greater than zero. It's true. And B is less than five. That is true. And then true and true will return. True. So we deal with boolean inputs and we have boolean outputs. But now consider that every object in Python has a true value. We have this concept of truthiness and so for any object we really could write the following. We can write bool X and will Y. That is perfectly legal. Since X has a true value, we can get the truth value by calling bool on X and we can get the true value of Y by using bool of Y and we can do the same thing or as well. So the thing is that we actually don't have to write bu here. In fact we can just write X and Y or we could write X or Y, that will work perfectly well. Python will use the truthiness of X and the truthiness of Y to get our results and to evaluate X and Y and X or Y. So the question then becomes is what is actually returned when we write this expression here where X and Y are not booleans, but just objects that have an associated truth value, what is being returned? Is that a boolean? And the answer is no, it's not. It's not a boolean, so let's see what's going on and let's see how Python actually defines it and and our operators. So let's start with four and I'll just bring back the truth. Table four right here. So X or Y is defined this way, if X is Truthy, it will return X, otherwise it returns Y and Bob Bobby is a little puzzled by what's going on. This isn't kind of the standard thing we think of when we think of the or operator. It's not a traditional way of teaching it. So it doesn't work as expected with just boolean values. If we just use X and Y as booleans, does this at least seem to correspond? So let's take a look. Let's just run through the different options. So let's take X and Y both false. So the rule is X is false. So we are going to return Y because the rule is that if X is Truthy, we return X, otherwise we return Y. So X is false. So we return Y, well, Y zero in this case. So we get false. Right. And I'm using zero and one as true and false. So if X is true, is false and Y is true, then X is false. So we still return Y. So in this case we return one and so far we're matching. Right. Zero zero return zero zero one. We have a one. So far so good. What about one zero where X is true and Y is false. Well, X is true, so we need to return X and so we return one and the still matches are regular truth table. Finally, if we take both of them equal to true, well X is true. So we still return X, which means we return true. OK, now one thing to note here is that if you look at what's happening, if X is Truthy, we return X, otherwise we return. Why did you notice that we never actually look at the value of Y. We never do, right, and if you look at the truth table, that kind of makes sense, because if X is true, well, we're always going to return. True. It doesn't matter what Y is. Now, if X is false, then we just return why we don't have to do another operation to find the OR if X is false. We know that the result is going to then be totally dependent on Y. So a better way to define this in terms of what's actually happening is that if X is Truthy, we return X, otherwise we evaluate Y and return it. And the reason why I want to write it this way is because now you'll notice that we don't actually evaluate y unless we need to return it. And you remember this whole short-circuiting thing we talked about in the last video. That's what's going on. That's why Y is not getting evaluated unless it has to. Right. So if the first part of the the first operand is true, then we just return. True, but we never evaluate the second part. If the first operand is false, then we have to evaluate and return Y because Y doesn't have to be a pure number or a pure boolean. It could just be an expression, could be a function call or something that is that returns either a boolean or an object that has an associated truth value. So that's the reason why we have this definition here and it actually works. It's kind of pretty cool, actually. And in fact, the orenda and operators return an object. They return one of your operands, either X or Y, depending on what the weather is, Truthy or not. So let's look at end and is defined very much in the same way, but if you think of the end, well, if the X is false, we always return false. If X is true, then we have to return Y. You'll notice that these two zero one zero one match here and the zero zero zero zero match here. So if you think about it a little bit, you can probably come up with a definition yourself, which is if X is false, return X, otherwise return Y. All right. So let's take a look at X and Y. If X's falsey return X, otherwise return Y. So, again, does this work as expected with Boolean values, so let's take a look, let's just run through it very quickly. If we have false well, X is false, right? So we return X, so our result is false. That matches next one. If X is false and Y is true, while it still doesn't matter, we should still return X, right according to this rule, and we return zero, which matches what we have in the truth table if X is true and which is false while X is true. So now we have to return Y. So in this case we'll return zero, which again matches our truth table. And similarly, if both are true, then because X is true, we have to return Y and therefore we return true, which is exactly what we have in the truth table. So this checks out as well. Now for the same reason that we discussed with the owner why it doesn't actually get evaluated unless it gets returned. So again, we have the Short-circuiting because if X is false, then we are just going to get false back and this Y will never get evaluated. So our definition really is if X is false, return X, otherwise evaluate Y and return it. And again, we have the Short-circuiting and this will then return the objects, the operands that we pass in the upper house could be booleans, which case we get the usual normal results or we could pass in any object. So let's look at the consequence of this with the operator first. What is a consequence of it? So again, just bring back our definition. If X is Truthy, we return X, otherwise we evaluate and return Y. So again, this does both the definition and also handles the SHORT-CIRCUITING. So let's take a look at this example here. Let's say that X is none. And why is this string and a then X or Y? Well, X is falsey, so we're going to return Y, which means we return and a. Similarly, if X is an empty string and wires and a while, the empty string is also faulty, so we're going to return any on the other hand, if we take X equal to hello and Y equal to and say, well, in this case, hello is a truthy string right at Truthy object. So we are going to return X, which means we return. Hello. So you'll notice that in both these cases here where we had a string that was either none or empty, we returned and. And when I say a string, we had a variable that was none or an empty string where we turned away. And in the case where our variable was a string with characters, we returned the string itself. So if we write something like this, A equals S or an A, then if S is none, we return any. If S is an empty string, we return any. If S is a string with characters we just return. S right. And we assign that to a. So this is basically a way to set up default values for a variable. Right. So we may be dealing with a string of we don't want to have an empty or none variable there so we can do X equals S or an eight. And this will ensure that A is always going to be a string, right? It's always going to be well, it's always going to have something in it. This is making the assumption that S is a string or is pointing to a string. But anyways, you get the idea so we can use this for setting up default values. So let's take a look at an example. Because we can expand this further, we can say a equals one or two or three or an eight. And this will then be so they will be equal to the first truthy value. And it's the first ruthe value, because as we mentioned before, in a case like this, we have these multiple or operators, Python will then evaluate them from left to right because these are all operators with equal precedence. So it will do a left-to-right evaluation. So essentially it's going to grab the first Truthy value. And since the last one is always Truthy, you're ensured that A is going to be at least an eight or it's going to be the first non-empty string and as one as two or three. So you can expand that a little further. So that's really handy when you're working with variables, and especially if you're pulling data from places that you don't really know, like maybe a database that could have nullable string fields or TextField or maybe it's from an API feed from somewhere or whatever it is, it can be really handy to do things like this. Let's take a look at another example. Let's say we have an integer variable that cannot be zero for some reason or other. We have this integer and we don't want it to be zero. And if it is zero, we want to set it to one. Now, obviously, you could write an if statement. If A is equal, equals zero, then equals one. You could do something like that. Or since zero is a faulty value, we can just write A equals A or one. It's going to be the same thing. It's going to return one if a zero or it's going to return A if A is non-zero. So again, pretty handy to do. Let's look at some consequences of and now and what we can do with it. So again, just recall that X and Y, if X is faulty, we return X, otherwise we value it and return Y. So let's look at this example, let's say X has a is an integer with a value of ten and Y is twenty, divided by X, then X and Y will return Y, right. Since X is Truthy, we will return Y, we will then evaluate Y, which is twenty, divided by two, by ten, which is two. And that's what gets returned from the X and Y. On the other hand, let's say that X was zero and Y is also twenty over X, then it's going to return zero because X is falsey. It's going to return that it will not even try to evaluate twenty divided by X. So it looks like we were able to avoid this division by zero error by using the end operator. And this is a pretty standard way as well. We can say X equals eight and total divided by eight. Let's say we're trying to calculate an average where we have maybe a sum like total and account the number of samples, which is a and at any point in time we could have a count that a B zero. We don't know. Right. Maybe it's right at the beginning. We haven't entered data yet. We're trying to compute the average. Well, this will then return a it will not try to do the division by zero, but if A is greater than zero, then it will do the actual computation. So again, very handy to have. So as an example, if we have a equals ten, well, ten and total divided by ten, that's going to return total divided by ten. Right. But if is equal to zero then we have zero and total divided by zero that's going to return zero. OK, so that avoids basically that division by zero error. Again, that's a pretty standard trick that can be used in Python. Let's take that example with the average that I was talking about, so let's say we have some an end, so sometimes end is non-zero. Sometimes it is. In either case, the average is NP and some divided by N, because if and zero, we have no count, right. Then the average is zero. So we want to return zero. On the other hand, if we do have values so N is non-zero, it's going to be some positive integer, then we do want to take some divided by N that will be the average. Here's another example. Let's say you want to return the first character of a string s or an empty string of the string is none or empty. In other words, we have a string and we want to bring back the first character of that string. But of course, if the string is not or empty, we just want to bring back the empty string. So let's see how we could do that. Here's one option. If s return is zero, otherwise return the empty string. Well, yeah, that will work, right? If S is none or if S is a string of Lenth zero is it's going to be faulty. Right. So it's going to return this empty string here. But if X is a string with characters then its length is greater than zero, which means that it's going to be Truthy and we're going to return as zero. Option number two, which works equally well and actually works maybe well, actually works equally well, we can say return S and S zero. Now, it's not option to return S and S zero. Well, that's kind of OK, right? Because if S is none or the empty string, then it's going to return S because it's going to be faulty, otherwise it will return the false character. So this will not create an error. We won't have an exception. This will work just fine in all the cases where S is none, as is an empty string or S as a string of characters. However, what is it going to return when S is none, right? It doesn't work well with a known case. It's not going to do what we want it. We want it to return an empty string. If the string is none here, it's going to return none if S is none. So how can we fix that? Well, we can take whatever this returns and we can orit with the empty string so that if the return of this thing here is faulty, which means none, all the empty string, we're going to replace it with the empty string so we can do it this way. Return S and S zero or the empty string. And that will do exactly what we want. In fact, you can make this default value now whatever you want so you can have it will return the first character of the string or maybe it returns any if you want, if it's an empty or none variable. And of course, Bob thinks that's really cool. I do, too. But that's kind of a cool way of doing this. It's you know, it's a one liner. And once you get used to it, it's very easy to recognize this pattern and to understand it. And you don't have as wordy code as you have over here. So lastly, let's look at the Boolean, not operator. Now, the knot is really a built in operator that returns a boolean value. So it doesn't work quite the same way as and an or and an overall returning objects. Right. It doesn't do that. It actually returns a honest boolean value. So if you do not X, then the way it works is that if X is faulty, then it will return. True, right. Because X is false. So we return not false, which is true. And it will return false. The Boolean false if X is Truthy. So it can still take any object here, but the knot will actually return the knot of the true value of the object. So if we take an empty string, for example, which is falsey, then not an empty string, it's an empty list, it's still an empty sequence, then not this empty sequence will return. True. On the other hand, if the sequence contains objects, it is Truthy and therefore not of that will actually value it to false. Similarly, if none is faulty, then not none will be true. So let's go ahead and actually switch to some code and we'll take a look at all of that in action in the next video. So thanks for watching. I'll see you in a bit.