Reputation: 573
I am reading about booleans in my book, and it says:
x and y------------If x is false, return x. Otherwise, return y.
x or y--------------If x is true, return x. Otherwise, return y.
This doesn't make sense to me from the everyday usage of "or" and "and" To me, it would make sense if it said:
x and y------------If x is false, do nothing. If y is false, do nothing. If x and y are true, return x and y
x or y--------------If x is true, return x. If x is false, check y. If y is false, do nothing. If y is true, return y
Do I just need to blindly accept the actual definitions, or can I understand them because they actually make sense.
Upvotes: 0
Views: 157
Reputation: 4476
The behavior may seem strange, but consider the following hypothetical examples. Starting with something obvious,
>>> True and False
False
>>> False and True
False
this is really easy to understand since we're dealing with boolean values. Remember this example, because every other example can be thought of this way.
Now consider if the and
and or
operators were to convert every object to a boolean before comparing. For example, an empty string or empty list would be False
, and non-empty ones would be True
. It would look like this (obviously this is not what it ACTUALLY looks like)
>>> "vanilla" and ""
False
>>> "" and "vanilla"
False
This makes perfect sense. After all bool("vanilla") and bool("")
would be the same as True and False
which we already know is False
Instead of actually converting them to True
or False
, though, it can do the comparison without ever converting them. As a result, you don't really need it to return True
or False
. It can just return the actual object it tested.
>>> "vanilla" and ""
""
>>> "" and "vanilla"
""
For truth testing purposes, returning ""
is the same as returning False
, so there's no need to convert it to a boolean. That's why it always returns an object whose truth value is the same as the result of the operator.
Upvotes: 1
Reputation: 457
Its probably easier if you think about it in each literal case
x and y------------If x is false, return x. Otherwise, return y.
x or y--------------If x is true, return x. Otherwise, return y.
CASE 1: x = true, y = true
"if x is false, return x. Otherwise, return y."
Then this will return y which is true. This makes sense because x and y are both true.
(true and true == true)
"If x is true, return x. Otherwise, return y."
The this will return x which is true. This makes sense because one of x or y is true.
(true or true == true)
CASE 2: x = false, y = true
"if x is false, return x. Otherwise, return y."
Then this will return x which is false. This makes sense because x and y are not both true.
(false and true == false)
"If x is true, return x. Otherwise, return y." The this will return y. This makes sense because one of x or y is true.
(false or true == true)
CASE 3: x = true, y = false
"if x is false, return x. Otherwise, return y."
Then this will return y which is false. This makes sense because x and y are not both true.
(true and false == false)
"If x is true, return x. Otherwise, return y."
Then this will return x which is true. This makes sense because x or y is true
(true or false == true)
CASE 4: x = false, y = false
"if x is false, return x. Otherwise, return y."
Then this will return x which is false. This makes sense because x and y are not both true.
(false and false == false)
"If x is true, return x. Otherwise, return y."
The this will return y which is false. This makes sense because neither x nor y is true.
(false or false == false)
Upvotes: 0
Reputation: 780673
Many (most?) programming languages, including Python, implement short-circuiting in their boolean operators and
and or
. So they evaluate their operands from left to right, and stop as soon as the final result can be determined.
Since x and y and z and ...
is guaranteed be false if any operand is false, it stops evaluating the operands as soon as it encounters a false one. And x or y or z or ...
is guaranteed to be true if any operand is true, so it stops as soon as it reaches a true operand. In either case, if they make it all the way to the last operand, they return its value.
In some languages, the boolean operators just return a strict boolean result, either true
or false
(in some languages these are represented as 1
and 0
). But in Python (and some others, such as Javascript and Common Lisp), they return the value of the last operand that was evaluated, which determined the final result. This is often more useful than just the truth value of the expression.
When you put these features together, it allows some succinct idioms, e.g.
quotient = b != 0 && a/b
instead of
if b != 0:
quotient = false
else:
quotient = a/b
Upvotes: 1
Reputation: 51
While the book presents it in a slightly confusing way, it is correct. Boolean logic must evaluate to either true or false.
For X and Y in order to return true they both must be true, if X is false then it returns false. If X is true then it returns Y which is either true or false and also the correct answer.
For X or Y to return false they both must be false. If X is true then it can return true (X). If X is false then it returns whatever the value of Y is.
Upvotes: 1
Reputation: 6693
Your book is right - see the documentation. It might be unintuitive at first, but this behavior (called short-circuiting) is extremely useful. In a simple case, it allows you to save a lot of time when checking certain conditions. In this example, where function f
takes 10 seconds to evaluate, you can definitely see one use:
if f(foo) or f(bar) or f(baz):
If f(foo)
is True
, then there is no need to evaluate f(bar)
or f(baz)
, as the whole if statement will be True
. Those values are unnecessary and you'll just be wasting your time computing them.
Another extremely common use of this behavior is in null (or for python None
) checking. It allows safe usage of functions all within one line:
if obj != None and obj.foo():
If obj
is None
, the if statement is guaranteed to be False
, and so there is no need to check (or even evaluate) obj.foo()
, which is good, since that would cause an exception.
Short-circuiting is very common in many programming languages, and is very useful once you fully understand how to use it.
Upvotes: 1
Reputation: 599470
The first set of descriptions are shortcuts: following these will give you exactly the same results as the "usual definitions" of true and false.
But your own descriptions don't make much sense. You can't "do nothing"; you have to return some value from a comparison, either true or false. And you can't return both a and b, either: again, the result of a boolean comparison must be a boolean, not a pair of booleans.
Upvotes: 0
Reputation: 11697
Unlike some other languages, you can use any object as operands of boolean operations. All your books says is that you can use boolean operators as a quick "filter" of values.
For instance, say you want to choose a non-empty list between two lists. The following is a valid (and more Pythonic) way to do it:
>>> [] or ['something', 'here']
['something', 'here']
Contrast to (not making use of Python idioms in Python):
if len(l1) != 0:
return l1
else:
return l2
Upvotes: 1
Reputation: 13171
"Do nothing" isn't an option. The mathematical expression x or y
must have a value (which is true if either x
, y
, or both is true). And x and y
must have a value (which is true if and only if x
and y
are both true).
The way your book defines them is mathematically correct, but confusing (until you get into things like short-circuit evaluation).
Upvotes: 4