 In this video we're going to learn about the Boolean data type that will prepare us for looking into more detail into conditions and the if statement in the next video. So let's open a new file and let's call it Booleans and let me give you an example. So we have seen previously that whenever we compare a left hand side to the right hand side we get back either a true or false answer. So let's look at an example. Let's compare the number 42 maybe to the number 43 and we get back false. And let's have a second example. Let's compare the number 42 to the floating point number 42.0 and now we get back true. So true and false are Python's way of saying yes or no and they are special built-ins. So in other words, if I go ahead and I type true or I type false, Python immediately knows what we mean. So it's built-in and note that the t and the f are uppercase, so lowercase will not work. And both objects of the same data type, so type of true is bool, short for boolean and the type of false is also bool, also for boolean and these are the only two objects of this data type. So there's not a third or fourth object of this given data type. One short note, we should not confuse false in particular with another object which is called none. So none is a special object that we did not talk about explicitly in the previous videos, but we encountered none already when we work with functions. So whenever we write a function but we don't specify a return statement inside the function's body, so the function has not an explicit return value, then implicitly the none object is always going to be returned. So let's see that what is the data type of none? The data type of none is simply the none type. So here we see that none and false are two different objects of different data types. However, one thing that I already say that true and false sometimes behave similarly. So therefore they are often confused, but let's simply write here, false is not none. And you know what I want to say here. Just don't confuse the two, okay, they are different objects. So let's use a bit more grammar. So the first two code cells that we see here are examples of what we call Boolean expressions. So any piece of code, any expression that evaluates into either true or false is what we call a Boolean expression. And I will give you a couple of more examples. So but we will introduce another concept. And the other concept is that of the so-called relational operators. So relational operators are simply operators that take a left-hand side and the right-hand side and compare the two sides with each other. So to say the left-hand side is related somehow to the right-hand side, we've seen the double equal sign up here. So the double equal sign is briefly copy paste it down here as well for completeness sake. The double equal sign is the comparison operator. And if we want to check for the opposite, what we could do is we could compare the number 42 or if the number 42 is not equal to the number 43, we do that with exclamation mark equals. So that's simply the opposite. So that's why we get back through here. And note that in a couple of other programming languages, you may see the smaller than crater than symbol like this to indicate not equals to. But in Python, this is simply exclamation mark equals. So there are in total four more relational operators and they adhere to what we know from mathematics. So if we want to ask the question, is the number 42 smaller than the number 43? It's of course true. And similarly, we could go ahead and compare if the left-hand side 42 is smaller than or equal to 43. This would also work. And then two more examples. Let's go ahead and compare 42 and ask the question, is it crater than strictly crater than 43? And the answer would be, of course, false. And then let's do one more example here. And the example will be if 43 crater than or equal to 42. And now we have seen all six relational operators. So whenever we use a relational operator, the result is of course always a boolean expression. So it's going to return us a boolean. So a true or false, one of the two objects. So yeah, so that is relational operators. And now let's ask the question, how can we compare different, different, or how can we connect, that's better term, how can we connect different boolean expressions together? And we do so with another breed of operators, these are the so-called logical operators. So let's maybe summarize them, connect different boolean expressions together to form a bigger one then, of course. So let's do an example. Let's go ahead and set A to 42 and let's set B to 87. And now we could ask the question, for example, is A smaller than five? And at the same time is B, let's say smaller than or equal to 100. And let's execute that and the answer is false. And the reason for that is because the left-hand side here is of course false. So in other words, we can say and becomes or evaluates into true only if both sides are true. And because the left-hand side, the boolean expression on the left-hand side evaluates into false, that means it doesn't even matter what the right-hand side is. So the right-hand side is of course true, but it's not enough. So the overall expression is false here. Let's do a different example. So let's simply copy paste this. And let's turn around the left-hand comparison operator here. And now we get it true. Okay, so if both sides are true, then the overall result will be true. Sometimes people are confused about the order of precedence here. So what that means is sometimes you will see people put a pair of parentheses around the left and the right-hand boolean expressions. So as to indicate that the relation operators are executed first and then the logical one after that, but note that this is not necessary. The rule is that all the relational operators will always be executed first before all the logical ones. So no need to do that. Okay, let's introduce two more logical operators because there are only three actually. So let's go ahead and take our first example. And now remember that the left-hand side is false, the right-hand side is true, and therefore the overall result was false. However, if we replace the end operator with the or operator, I get back a true. Okay, so the idea of the or operator is becomes true if either side is true. And to avoid some confusion for some beginners, if either side is true or of course both sides are true. Okay, so if I take the second example from above where both sides are true and I copy and paste this down here and I replace the end with an or, the answer is of course also true. Okay, it is enough that one of the two sides is true. And then the overall result will be true. So sometimes what you want to do is you want to negate the truth value, so to say, of an object. So you want to convert true into false and false into true. We could also say we flip the truth value. There's an operator for that. And the operator for that is the so-called not operator or not. And let's just simply say flips the true and false. So let's see an example of that. So if I ask the question, is a smaller than five, the answer is false. But if I go ahead and negate that with a not, the answer becomes true. And also here, sometimes what you see is people will put parentheses here because they are not sure if the relational operator will be executed first, but the answer is it is. So as I said, the rule is that all the relational operators are always executed before all the logical ones. However, for the logical operators, there is a order of precedence. So in other words, an order of execution. And the order goes like this. All the nots have the highest binding power. Then comes the ands. And lastly comes the ors. So let's maybe go ahead and come up with another example. Let's say a is smaller than or equal to 100 or not, b is greater than 100. So the overall result is true, but let's now break it down why it is true. So if we want, if we see an expression like that, the way to read it is we know by now that all the relational operators go first. So we could think of implicit parentheses b here. And then the not has a higher binding power than anything else. So it goes like this. And then the or will basically connect the truth value of the last hand side with the truth value of this expression. So this is how Python would read it. Okay. And again, the end is not in here. But yeah, so sometimes let's do another example. So let's say a is smaller than let's say 40 and b is greater than 100. Or b is smaller than or equal to 90. Let's see what the result is. It's true. But now how does Python do that? Well, Python will go ahead and the relational operators are all executed first. So let's put parentheses here. And now the next couple of parentheses will go around the end here. Okay, because the end has the higher binding power than the or. So we see that the result does not change. So that is the order of precedence for the logical operators. And these three logical operators, they have an interesting theoretical property. With them, you can express anything that can be expressed mathematically. So they are enough to express any truth or false statement about the world, so to say in code. And they are more than enough. Some programming languages have other operators. So additional logical operators, but Python only has those three. And any other logical operation that we want to implement, we would have to implement using those three here. But it can be proven that this is doable. Okay, so these three are enough to model any logical idea that we want to model. So let's see what else is there to learn. So let's say one nice thing about Python is if I want to check, let's say if A is in the interval of let's say 10 and 50. I can just do that by chaining the operators. So here that is an example of what we call operator chaining. And that would be of course the same as if, let's go ahead and do the not chained way. This would of course be the same as if we went ahead and we wrote the same expression, but we write it like this. So 10 smaller than A and A smaller than 50. That is basically the long version and the chained version, the operator chaining version here is the short version of that. So whenever you see two operators chained together like this, then you can implicitly expand the A in the middle as A and A. So that is often what you see. This is something that a couple of programming languages support. Python does some other stoned, but this is in particular nice when you work with numbers, for example, when you want to express the idea that some number is in a range of two other numbers or not. Okay, so that's a nice thing to know. And now let's go ahead and introduce another nice idea, the idea of truthy. So let's execute this also. We see it's the same. Well, now comes the next idea, the idea of truthy versus falsy. So what this is, this may look a bit weird in the beginning, but we will see when we work with the if statement in the next video, that knowing this will prevent us from making further logical mistakes. So let's say I go ahead and I say, A, which is 42, if I go ahead and I say, if A is smaller than, let's say 40. And at the same time B, let's say minus 100 or let's say B minus, yeah, let's say B minus 100. And then let's simply not do anything here. And that is quite interesting. So why does this work? So why does this first of all not give us an error? Because if we watch closely in the example on the left hand side, I have a relational operator on the right hand side. I forgot, for example, the relational operator. I mean, this could this could read like B minus 100 is smaller than, I don't know, 2000. And maybe I simply forgot the smaller than 2000. This often happens, but we don't get an error here. So on the right hand side, I have an arithmetic expression, not a Boolean expression. However, the and operator doesn't really care. And the reason why is because the and operator what it really does is it looks at the left hand side and checks if this is a Boolean value. It gets back as well either through a false and it does so in the same way for the right hand side. However, if it does not get back a true or false, it does the following. It calls the bull constructor. So just note how we learned about constructors in the previous video. And when we talked about data types and the bull data type, of course, also works as a constructor. So let's use the bull constructor and let's pass to it a smaller than 40. And that's why it and bull of B minus 100. So this is basically what Python does in the background. Whenever you write an expression like that using a logical operator. So the logical operator needs a Boolean on the left and the right hand side. But in this example, I don't give it a Boolean. So B is 87. So 87 minus 100 is minus 13. So that the right hand side is negative 13. It is not a Boolean. However, it does not complain. And the reason why is because Python, if it does not, if it is not given a Boolean here, then it just converts whatever it gets into a Boolean by using the bull constructor. And it's now break this down into two separate steps. So if I go ahead and simply copy paste the left hand side here, I get back a false. And if I copy paste the right hand side here, I get back a true. So you may wonder why is that a true case? So if I go ahead and remove the bull, it's negative 13, as I said. But if I write back bull, then what we see here is that a negative number is considered true. So the rule is any number other than zero is true. So let's confirm that. Let's go ahead and write bull of zero. And indeed, we get back false. And if I write, let's say, bull of one, I get back a true. But if I also write bull of negative one, any negative number works, I also get back a true. So in other words, you have to be careful that if you write just because you write an expression like the logical operator and here that requires some Boolean values and they don't complain if you don't give a Boolean value to them. They just convert whatever you give them into a Boolean value themselves. And sometimes you hear programmers say an object is truthy if it behaves like true in a Boolean context. So that is what we say. And then for false, it's the same definition. An object is considered false if it behaves like false in a Boolean context. And what do we mean by context? In this example here, we just mean we use the logical operator and that requires Booleans on both sides. That is the Boolean context. Okay, so that is truthy versus false. So we will see an example of that in an if statement in the next video where I will on purpose make a mistake and then you will immediately know what the mistake is. And also note in the chapter, you will see a couple of other rules for how the bull constructor works. For example, if we go ahead and we give the bull constructor a list and the list contains the number zero, it is still considered true. So in other words, the rule is the rule any non-empty list is true. So in other words, if I remove the zero here, the bull will be false. So an empty list will also be false. So this is also something that goes into this subsection here, truthy versus false. Okay, so and now let's also see in the beginning of this video, I told you that there is a special value called none and people often confuse it with false. So now let's see why. Now that we know the bull constructor, let's use the bull constructor and pass to it none. And we will get back false and that is the false friend here. Okay, so maybe let's write false friend. Let you remember why. So none behaves like false important in a Boolean context. So that is why it's often confused. So note that none is not false, but it behaves like false, but only in a Boolean context. So that is where the idea of a false friend comes from here. Okay, so also let's do a last section in this video and section title will be short circuiting. And here I will show you a couple of details about how the logical operators work. So in other words, let's write the logical operators and execution once the result is determined. And we actually saw an example of that. So let's go back up here. I think it was here the first example. So it was this example here. So note that this example here on the left hand side, a smaller than five, a is 42. So the left hand side is already false. So the question is the end operator becomes true only if both sides are true. However, if the left hand side is already false, it is not worthwhile to check the right hand side, right? So in other words, it does not make sense from a computer computational perspective to look at the right hand side at all, right? Because the result is already determined solely by the left hand side. And that is an example of short circuiting. So the execution from left to right stops once the overall result is there. So let's take this down here and copy paste it down so that we have one example here. So the right hand side is not executed. And now let's also look at a couple of more details of how and and all work. So above, I said the whole point of having logical operators is to connect different Boolean expressions together. However, in Python, the logical operators work a lot more in a lot more generic way. So let's go ahead and write five and nine, for example. And interestingly, I get back to number nine. So you may wonder how can how can it be that and gives me back to number nine here? Okay. So in other words, and does not even care about what I give it. And we saw that above in the discussion with Ruthie was a foresee that if the left hand side is in this case a number. What Python does behind the scenes is it will put it inside the bull constructor. And then it will get back in this case because the number five is not zero. It will get back through. And then Python will go ahead and will evaluate the right hand side. And the right hand side, the Boolean of nine is also true. And then it returns not the Boolean of the right hand side, but it returns the right hand side itself. Okay. So that is the rule here. And similarly, if I go ahead and say, let's say zero and nine, I get back the number zero because zero in a Boolean context that is falsely. So it's just it behaves like false. Therefore, the end operator knows that it does not even have to look at the right hand side. Why? Well, because the left hand side is already falsely. So it doesn't even make sense to look at the right hand side. Therefore, the result is determined solely by the left hand side. And the precise operation of the or working of the end operator is it does not give us back a true or false. It just gives us back the argument itself. So that is why I get back the zero here. Okay. So this is also a source of confusion that and and also the other two operators not and and or they work with any operator. You give them any data type that not that somehow can be handled by the bull construct in the background. And the reason why I put this in the video here is because I want to make you aware of that because oftentimes when you want to write an if condition like this and you make a mistake, you forget to put some relational operator somewhere or maybe one operand is not true or false at all. Then you may get weird results and the weird results can often be explained with the fact that the logical operator does something that you don't expect it to do. And so now in this video, I talked about all the details of the logical operators. So if you get a weird result, then in your example, you maybe should break down the entire line, the entire expression and see that, you know, and check if you maybe give it a non boolean expression that then behaves in a boolean context somehow. And then maybe you get back weird results. Okay. So that's the idea of short circuiting. So yeah, so that is how how the booleans work in Python roughly. And in the next video, we will see what we can do with booleans. Namely, we can use them to formulate if conditions and to implement some if else logic. And that is probably the number one application of booleans. Okay. So I see you in the next video.