Use of Boolean Logic: And/Or And True/False - python

I'm learning basic Boolean logic with Python. I understand the equality operators but get confused when ands and ors get thrown in. Take a look at the following code for example:
people = 20
cats = 30
dogs = 15
if people < cats:
print "too many cats! the world is doomed!"
if people == cats or dogs == cats:
print "this is too hard"
I understand the first if statement and why it prints. i don't know how the second if statement is evaluated. How could I change it to get that line to print?
Thanks for your help!

and requires that all of its parts in the expression evaluate to True for the whole expression to be True.
or is much less picky, as soon as any part of the expression evaluates to True the whole expression is True.
You may come across the term short-circuiting in this context. It simply means that we stop evaluating expressions as soon as we can determine its outcome.
So for an and we can stop looking at the rest of the expression as soon as we find a part that evaluates to False because at that point the expression can never evaluate to True.
Likewise, with or, as soon as we find a part that's True, we know the whole expression will be True and there won't be a reason to look further.
For the code example you posted:
if people == cats or dogs == cats:
print "this is too hard"
if either one of these, or both of people == cats, dogs == cats evaluated to True, the whole expression in the if statement would become True. Since neither of them are True, the expression in the if statement fails, i.e., is False, and the print statement is not executed.
Finally, if you wanted to print statement to execute, you'd have to ensure that the Boolean expression evaluated to True. One way would be to change to value of
dogs to 30 because then dogs == cats would be True and that would be
sufficient to make the whole expression True and get the print to execute.

OR tests if both or one statement is true, AND tests if both statements are true.

The if statements are both evaluated the same way.
if something:
do_stuff
If something is True, then the do_stuff block is run[1]. If something is not True then the do_stuff block is not run. The difference between your two if statements is not that one "works differently" than the other, but that they are run on different versions of something.
and and or are binary operations that take truth values and compute new truth values. Much as in 1 + 3 the + is a binary operation that takes the numbers 1 and 3 and produces a new number 4. a and b takes the two truth values a and b and produces a new one. And much as we can have either x + y or x * y that produce different numbers from the numbers x and y, we can have a and b or a or b, which produce different truth values from the truth values a and b.
But the if statement doesn't care about that. It doesn't need to know how we got the truth value it's testing, it will work exactly the same either way. and and or are entirely separate, they're just ways of combining truth values to get new ones.
The intuition for how and and or work is based on some ways that we use and and or in English when talking about things that can be either true or false.
In the statement "If it is raining then I will get an umbrella", the "it is raining" part is a condition that could be either true or false, and the rest of the sentence is saying what will happen if it's true. In English I could also say "If it is raining and I feel like walking then I will get an umbrella"; this has the two separate conditions "it is raining" and "I feel like walking" combined into one condition by the word and. This sentence means I will get an umbrella if both "it is raining" and "I feel like walking" are true; if it's sunny then I don't think I need an umbrella, and if I'm driving then I don't care about getting wet between my house and the car.
I could also have said "If it is raining or I feel like walking then I will get an umbrella". This sentence means that I will get an umbrella if either one or both of the conditions are true. Here we could guess that if it's raining I want to have an umbrella for later in the day even if I don't feel like walking, and if I feel like walking I want to have an umbrella in case it rains later during my walk, even if it's not raining now.
The best way to understand truth values in programming and the and and or operators is to keep this natural understanding of English and and or in mind. This gives you an intuitive way of quickly understanding simple expressions involving and and or. But in programming the way and and or works is formalised, so we can write down exactly how they work, regardless of any ambiguities or special cases in normal English usage.
A and B is True if A is True and B is True, and False otherwise (it is False if either A or B is False). A or B is is True if either A or B is True (it is False if A is False and B is False, and True otherwise). Here's a table that shows this:
A | B | A and B
------+-------+---------
True | True | True
True | False | False
False | True | False
False | False | False
A | B | A or B
------+-------+--------
True | True | True
True | False | True
False | True | True
False | False | False
[1] In fact, the story is a little more complicated than this (as is true for my whole answer). Most boolean operations in Python (including the if statement and the operators and and or) operate not on exact Truth values, but on "truthy" values. Briefly numbers that are 0, empty containers and strings, and the special value None act as if they were False when you give them to operations that expect truth values, and everything else acts as if they were True. We sometimes use the terms "truthy" or "falsey" to describe values that are not necessarily True or False but are acting as if they were.
Likewise, operations that produce new truth values from existing ones, like and and or do not necessarily return True or False, they might return a value you gave them that is "truthy" or "falsey" as required by the tables above.
But, if someone reading this is at an early stage in learning to program with truth values, I would strongly recommend you ignore this and just think of yourself as manipulating True and False, and likewise don't worry about "short-circuit evaluation" and the order in which things are checked (it doesn't matter if only genuine True and False are involved, or even most of the time when you're using other values). It's pretty easy to stretch your understanding to these concepts once you have the fundamentals down.

Related

Why any() and all() return different values on empty iterator [duplicate]

In Python, the built-in functions all and any return True and False respectively for empty iterables. I realise that if it were the other way around, this question could still be asked. But I'd like to know why that specific behaviour was chosen. Was it arbitrary, ie. could it just as easily have been the other way, or is there an underlying reason?
(The reason I ask is simply because I never remember which is which, and if I knew the rationale behind it then I might. Also, curiosity.)
How about some analogies...
You have a sock drawer, but it is currently empty. Does it contain any black sock? No - you don't have any socks at all so you certainly don't have a black one. Clearly any([]) must return false - if it returned true this would be counter-intuitive.
The case for all([]) is slightly more difficult. See the Wikipedia article on vacuous truth. Another analogy: If there are no people in a room then everyone in that room can speak French.
Mathematically all([]) can be written:
where the set A is empty.
There is considerable debate about whether vacuous statements should be considered true or not, but from a logical viewpoint it makes the most sense:
The main argument that all vacuously true statements are true is as follows: As explained in the article on logical conditionals, the axioms of propositional logic entail that if P is false, then P => Q is true. That is, if we accept those axioms, we must accept that vacuously true statements are indeed true.
Also from the article:
There seems to be no direct reason to pick true; it’s just that things blow up in our face if we don’t.
Defining a "vacuously true" statement to return false in Python would violate the principle of least astonishment.
One property of any is its recursive definition
any([x,y,z,...]) == (x or any([y,z,...]))
That means
x == any([x]) == (x or any([]))
The equality is correct for any x if and only if any([]) is defined to be False. Similar for all.
I believe all([])==True is generally harder to grasp, so here are a collection of examples where I think that behaviour is obviously correct:
A movie is suitable for the hard of hearing if all the dialog in the film is captioned. A movie without dialog is still suitable for the hard of hearing.
A windowless room is dark when all the lights inside are turned off. When there are no lights inside, it is dark.
You can pass through airport security when all your liquids are contained in 100ml bottles. If you have no liquids you can still pass through security.
You can fit a soft bag through a narrow slot if all the items in the bag are narrower than the slot. If the bag is empty, it still fits through the slot.
A task is ready to start when all its prerequisites have been met. If a task has no prerequisites, it's ready to start.
I think of them as being implemented this way
def all(seq):
for item in seq:
if not item:
return False
return True
def any(seq):
for item in seq:
if item:
return True
return False
not sure they are implemented that way though
Perl 6 also takes the position that all() and any() on empty lists should serve as sane base-cases for their respective reduction operators, and therefore all() is true and any() is false.
That is to say, all(a, b, c) is equivalent to [&] a, b, c, which is equivalent to a & b & c (reduction on the "junctive and" operator, but you can ignore junctions and consider it a logical and for this post), and any(a, b, c) is equivalent to [|] a, b, c, which is equivalent to a | b | c (reduction on the "junctive or" operator -- again, you can pretend it's the same as logical or without missing anything).
Any operator which can have reduction applied to it needs to have a defined behavior when reducing 0 terms, and usually this is done by having a natural identity element -- for instance, [+]() (reduction of addition across zero terms) is 0 because 0 is the additive identity; adding zero to any expression leaves it unchanged. [*]() is likewise 1 because 1 is the multiplicative identity. We've already said that all is equivalent to [&] and any is equivalent to [|] -- well, truth is the and-identity, and falsity is the or-identity -- x and True is x, and x or False is x. This makes it inevitable that all() should be true and any() should be false.
To put it in an entirely different (but practical) perspective, any is a latch that starts off false and becomes true whenever it sees something true; all is a latch that starts off true and becomes false whenever it sees something false. Giving them no arguments means giving them no chance to change state, so you're simply asking them what their "default" state is. :)
any and all have the same meaning in python as everywhere else:
any is true if at least one is true
all is not true if at least one is not true
For general interest, here's the blog post in which GvR proposes any/all with a sample implementation like gnibbler's and references quanifiers in ABC.
This is really more of a comment, but code in comments doesn't work very well.
In addition to the other logical bases for why any() and all() work as they do, they have to have opposite "base" cases so that this relationship holds true:
all(x for x in iterable) == not any(not x for x in iterable)
If iterable is zero-length, the above still should hold true. Therefore
all(x for x in []) == not any(not x for x in [])
which is equivalent to
all([]) == not any([])
And it would be very surprising if any([]) were the one that is true.
The official reason is unclear, but from the docs (confirming #John La Rooy's post):
all(iterable)
Return True if all elements of the iterable are true (or if the iterable is empty).
Equivalent to:
def all(iterable):
for element in iterable:
if not element:
return False
return True
any(iterable)
Return True if any element of the iterable is true. If the iterable is empty, return False. Equivalent to:
def any(iterable):
for element in iterable:
if element:
return True
return False
See also the CPython-implementation and comments.

Difference between if and if not python

Can anybody please tell me here what is the exact difference between if and if not here in the code.
def postordertraversse(self,top):
m=[]
if(top):
if not self.postordertraversse(top.left):
m.append(top.root)
top_most=m.pop(0)
conv=createlist();
conv.postordertraversse(conv.top)
What i can understand is if top means if top object instance exists then move inside the block and check if not i.e till top.left is not null keep appending.
if x: means "if x is truthy".
if not x: means "if x is falsey".
Whether something is truthy or falsey depends on what kind of object it is.
For numbers, 0 is falsey, and all other values are truthy.
For boolean values, True is truthy and False is falsey (obviously!)
For collections (lists, tuples, dictionaries, strings, etc), empty ones are falsey and non-empty ones are truthy.
So in your example code, the two if statements are saying:
if top is truthy:
if the result of self.postordertraversse(top.left) is falsey:
not in python is like negation in other programming languages.
'not' statement just converts further expression. For example:
not True - False
not False - True

True/False in lists [duplicate]

False is equivalent to 0 and True is equivalent 1 so it's possible to do something like this:
def bool_to_str(value):
"""value should be a bool"""
return ['No', 'Yes'][value]
bool_to_str(True)
Notice how value is bool but is used as an int.
Is this this kind of use Pythonic or should it be avoided?
I'll be the odd voice out (since all answers are decrying the use of the fact that False == 0 and True == 1, as the language guarantees) as I claim that the use of this fact to simplify your code is perfectly fine.
Historically, logical true/false operations tended to simply use 0 for false and 1 for true; in the course of Python 2.2's life-cycle, Guido noticed that too many modules started with assignments such as false = 0; true = 1 and this produced boilerplate and useless variation (the latter because the capitalization of true and false was all over the place -- some used all-caps, some all-lowercase, some cap-initial) and so introduced the bool subclass of int and its True and False constants.
There was quite some pushback at the time since many of us feared that the new type and constants would be used by Python newbies to restrict the language's abilities, but Guido was adamant that we were just being pessimistic: nobody would ever understand Python so badly, for example, as to avoid the perfectly natural use of False and True as list indices, or in a summation, or other such perfectly clear and useful idioms.
The answers to this thread prove we were right: as we feared, a total misunderstanding of the roles of this type and constants has emerged, and people are avoiding, and, worse!, urging others to avoid, perfectly natural Python constructs in favor of useless gyrations.
Fighting against the tide of such misunderstanding, I urge everybody to use Python as Python, not trying to force it into the mold of other languages whose functionality and preferred style are quite different. In Python, True and False are 99.9% like 1 and 0, differing exclusively in their str(...) (and thereby repr(...)) form -- for every other operation except stringification, just feel free to use them without contortions. That goes for indexing, arithmetic, bit operations, etc, etc, etc.
I'm with Alex. False==0 and True==1, and there's nothing wrong with that.
Still, in Python 2.5 and later I'd write the answer to this particular question using Python's conditional expression:
def bool_to_str(value):
return 'Yes' if value else 'No'
That way there's no requirement that the argument is actually a bool -- just as if x: ... accepts any type for x, the bool_to_str() function should do the right thing when it is passed None, a string, a list, or 3.14.
surely:
def bool_to_str(value):
"value should be a bool"
return 'Yes' if value else 'No'
is more readable.
Your code seems inaccurate in some cases:
>>> def bool_to_str(value):
... """value should be a bool"""
... return ['No', 'Yes'][value]
...
>>> bool_to_str(-2)
'No'
And I recommend you to use just the conditional operator for readability:
def bool_to_str(value):
"""value should be a bool"""
return "Yes" if value else "No"
It is actually a feature of the language that False == 0 and True == 1 (it does not depend on the implementation): Is False == 0 and True == 1 in Python an implementation detail or is it guaranteed by the language?
However, I do agree with most of the other answers: there are more readable ways of obtaining the same result as ['No', 'Yes'][value], through the use of the … if value else … or of a dictionary, which have the respective advantages of hinting and stating that value is a boolean.
Plus, the … if value else … follows the usual convention that non-0 is True: it also works even when value == -2 (value is True), as hinted by dahlia. The list and dict approaches are not as robust, in this case, so I would not recommend them.
Using a bool as an int is quite OK because bool is s subclass of int.
>>> isinstance(True, int)
True
>>> isinstance(False, int)
True
About your code: Putting it in a one-line function like that is over the top. Readers need to find your function source or docs and read it (the name of the function doesn't tell you much). This interrupts the flow. Just put it inline and don't use a list (built at run time), use a tuple (built at compile time if the values are constants). Example:
print foo, bar, num_things, ("OK", "Too many!)[num_things > max_things]
Personally I think it depends on how do you want to use this fact, here are two examples
Just simply use boolean as conditional statement is fine. People do this all the time.
a = 0
if a:
do something
However say you want to count how many items has succeed, the code maybe not very friendly for other people to read.
def succeed(val):
if do_something(val):
return True
else:
return False
count = 0
values = [some values to process]
for val in values:
count += succeed(val)
But I do see the production code look like this.
all_successful = all([succeed(val) for val in values])
at_least_one_successful = any([succeed(val) for val in values])
total_number_of_successful = sum([succeed(val) for val in values])

Python logic mnemonic

In answer to a question about Python and/or logic, Spacetoast wrote:
x and y returns true if both x and y are true.
x or y returns if either one is true.
I manage to confuse myself by using "or" when it should have been "and". Without having to drawing up truth tables, is there an mnemonic to help remember the correct usage of and/or?
Not a true Mnemonic, but NOAH has helped my students in the past.
How many inputs must be true?
None => Nor
One => Or
All => And
Honestly => Heed the truth tables
To be honest the skill of being able to use a truth table is worth persevering with. (Note there is not a NOR operator in python, its a Not-or).
The confusion from the pointed answer to that question come from the fact that he says the OR contains AND which is true in your case. There's is nothing to remember here, if you use or operator and at least one of the two expressions is True then it returns True if none of the two expressions are True it returns False
This means that if both x and y are True the or will be True too because as soon as the first expression x is True there's no need for evaluating the second one.
On the other hand, if you're using and and the first expression doesn't evaluate to True, there's no need to evaluate the second one, since it's impossible for both of them to be True anymore.
there is no need of mnemonic for this
remember this by a simple concept:
or -> any one true
and -> all true
true or false = True
true and false = False

Reason for "all" and "any" result on empty lists

In Python, the built-in functions all and any return True and False respectively for empty iterables. I realise that if it were the other way around, this question could still be asked. But I'd like to know why that specific behaviour was chosen. Was it arbitrary, ie. could it just as easily have been the other way, or is there an underlying reason?
(The reason I ask is simply because I never remember which is which, and if I knew the rationale behind it then I might. Also, curiosity.)
How about some analogies...
You have a sock drawer, but it is currently empty. Does it contain any black sock? No - you don't have any socks at all so you certainly don't have a black one. Clearly any([]) must return false - if it returned true this would be counter-intuitive.
The case for all([]) is slightly more difficult. See the Wikipedia article on vacuous truth. Another analogy: If there are no people in a room then everyone in that room can speak French.
Mathematically all([]) can be written:
where the set A is empty.
There is considerable debate about whether vacuous statements should be considered true or not, but from a logical viewpoint it makes the most sense:
The main argument that all vacuously true statements are true is as follows: As explained in the article on logical conditionals, the axioms of propositional logic entail that if P is false, then P => Q is true. That is, if we accept those axioms, we must accept that vacuously true statements are indeed true.
Also from the article:
There seems to be no direct reason to pick true; it’s just that things blow up in our face if we don’t.
Defining a "vacuously true" statement to return false in Python would violate the principle of least astonishment.
One property of any is its recursive definition
any([x,y,z,...]) == (x or any([y,z,...]))
That means
x == any([x]) == (x or any([]))
The equality is correct for any x if and only if any([]) is defined to be False. Similar for all.
I believe all([])==True is generally harder to grasp, so here are a collection of examples where I think that behaviour is obviously correct:
A movie is suitable for the hard of hearing if all the dialog in the film is captioned. A movie without dialog is still suitable for the hard of hearing.
A windowless room is dark when all the lights inside are turned off. When there are no lights inside, it is dark.
You can pass through airport security when all your liquids are contained in 100ml bottles. If you have no liquids you can still pass through security.
You can fit a soft bag through a narrow slot if all the items in the bag are narrower than the slot. If the bag is empty, it still fits through the slot.
A task is ready to start when all its prerequisites have been met. If a task has no prerequisites, it's ready to start.
I think of them as being implemented this way
def all(seq):
for item in seq:
if not item:
return False
return True
def any(seq):
for item in seq:
if item:
return True
return False
not sure they are implemented that way though
Perl 6 also takes the position that all() and any() on empty lists should serve as sane base-cases for their respective reduction operators, and therefore all() is true and any() is false.
That is to say, all(a, b, c) is equivalent to [&] a, b, c, which is equivalent to a & b & c (reduction on the "junctive and" operator, but you can ignore junctions and consider it a logical and for this post), and any(a, b, c) is equivalent to [|] a, b, c, which is equivalent to a | b | c (reduction on the "junctive or" operator -- again, you can pretend it's the same as logical or without missing anything).
Any operator which can have reduction applied to it needs to have a defined behavior when reducing 0 terms, and usually this is done by having a natural identity element -- for instance, [+]() (reduction of addition across zero terms) is 0 because 0 is the additive identity; adding zero to any expression leaves it unchanged. [*]() is likewise 1 because 1 is the multiplicative identity. We've already said that all is equivalent to [&] and any is equivalent to [|] -- well, truth is the and-identity, and falsity is the or-identity -- x and True is x, and x or False is x. This makes it inevitable that all() should be true and any() should be false.
To put it in an entirely different (but practical) perspective, any is a latch that starts off false and becomes true whenever it sees something true; all is a latch that starts off true and becomes false whenever it sees something false. Giving them no arguments means giving them no chance to change state, so you're simply asking them what their "default" state is. :)
any and all have the same meaning in python as everywhere else:
any is true if at least one is true
all is not true if at least one is not true
For general interest, here's the blog post in which GvR proposes any/all with a sample implementation like gnibbler's and references quanifiers in ABC.
This is really more of a comment, but code in comments doesn't work very well.
In addition to the other logical bases for why any() and all() work as they do, they have to have opposite "base" cases so that this relationship holds true:
all(x for x in iterable) == not any(not x for x in iterable)
If iterable is zero-length, the above still should hold true. Therefore
all(x for x in []) == not any(not x for x in [])
which is equivalent to
all([]) == not any([])
And it would be very surprising if any([]) were the one that is true.
The official reason is unclear, but from the docs (confirming #John La Rooy's post):
all(iterable)
Return True if all elements of the iterable are true (or if the iterable is empty).
Equivalent to:
def all(iterable):
for element in iterable:
if not element:
return False
return True
any(iterable)
Return True if any element of the iterable is true. If the iterable is empty, return False. Equivalent to:
def any(iterable):
for element in iterable:
if element:
return True
return False
See also the CPython-implementation and comments.

Categories

Resources