Logical Operators

code guest
Python Journey
Published in
10 min readAug 26, 2019

In the world of operators, arithmetic and string operations do things (ie. calculate / transform values) while relational operators checks the order of its operands. Another group of operators called logical operators help our programs to make decisions based on one or more conditions.

Here are some examples of conditions which are in bold and logical operators in caps:

  • Baby Bear would only eat porridge that is warmer than Papa Bear’s porridge AND colder than Mama Bear’s porridge
  • Winnie would only head out on a trip if Tigger is going OR if Piglet is going
  • Wolfie can only blow down a house if the house is NOT built with bricks

Notice the three logical operators → AND, OR and NOT.

Note that and / or / not operators in Python are in lowercase but this article presents them in Caps to differentiate them from other text.

Also, notice that the conditions (or operands) are affirmative or not affirmative — like the porridge is either warmer or not warmer, Tigger is going or not going and house is built with bricks or not built with bricks.

Logical operators can evaluate multiple conditions to arrive at a single decision (credits: undraw.co)

The AND and OR logical operators have these features:

  • AND and OR operators must work with two operands — one on its left and one on its right
  • ONLY if both operands are Boolean values (ie. True or False) or evaluate to True or False, then AND and OR operations themselves evaluate to True or False (similar to relational operators)
  • From the point above, we can see how AND and OR logical operators help to build more complex Boolean operations from simpler Boolean operations
  • AND and OR operators follow the same steps of evaluating its operands — left operand first, then right operand
  • If either one operand isn’t a Boolean value, then AND and OR logical operations check the boolean value of the non-boolean value operand(s) and give us one of the operand’s value instead
Depending on its left and its right operands, logical operations can result in either a boolean value or an operand value (credits: undraw.co)

And operator

If both operands are Boolean values themselves or evaluates to True or False, Python follows three steps:

  1. Python first checks the left operand and gives us False if the left operand is False or evaluates to False
  2. If the left operand is True or evaluates to True, Python checks the right operand. If the right operand is False or evaluates to False, the AND operation gives us False
  3. If the left operand is True or evaluates to True and right operand is True or evaluates to True, then the AND operation gives us True
True and True # Evaluates to True
True and False # Evaluates to False

If one operand isn’t a Boolean value, Python follows two steps:

  1. Python first evaluates the Boolean value of the left operand
  2. If the Boolean value of the left operand is False, then Python gives us the value of the left operand. Otherwise, the result returned is the value of the right operand.
False and "A" gives us False 
# left operand is False
[] and "A" gives us []
# boolean value of [] is False
"a" and "A" gives us "A"
# boolean value of "a" is True, so operation gives us "A"
"a" and False gives us False
# boolean value of "a" is True, so operation gives us value of right operand False
Both the AND and OR operators evaluate their left operand first (credits: undraw.co)

Or operator

If both operands are Boolean values themselves or evaluates to True or False, Python follows three steps:

  1. Python first checks the left operand and gives us True if the left operand is True or evaluates to True
  2. If the left operand is False or evaluates to False, Python checks the right operand. If the right operand is True or evaluates to True, the OR operation gives us True
  3. If the left operand is False or evaluates to False and right operand is False or evaluates to False, then the OR operation gives us False
True or False # Evaluates to TrueFalse or True # Evaluates to TrueFalse or False # Evaluates to False

If one operand isn’t a Boolean value, Python follows two steps:

  1. Python first evaluates the Boolean value of the left operand
  2. If the Boolean value of the left operand is True, then Python gives us the value of the left operand. Otherwise, the result returned is the value of the right operand.
False or "A" gives us "A"
# left operand is False so operation gives us value of right operand "A"
[] or "A" gives us "A"
# boolean value of [] is False so operation gives us value of right operand "A"
"a" or "A" gives us "a"
# boolean value of "a" is True, so operation gives us "a"
True or "A"gives us True
# left operand is True, so operation gives us value of left operand which is True

Not operator

Unlike the AND and OR operators, the NOT operator can only be used with one operand.

Basically, the NOT operator checks for the boolean value of its operand and return the opposite boolean value.

not [] # evaluates to True, because [] has boolean value of False
not 10 # evaluates to False, because 10 has boolean value of True

short-circuit evaluation

The expression on the left of the AND or OR operator is evaluated first: if the result is False — for AND operations, or True — for OR operations, Python does not (and need not) evaluate the expression on the right — this is called short-circuit evaluation.

Since both AND and OR operators take two operands, short-circult evaluation means that the right operand doesn’t get evaluated — which is really helpful if the right operand can give us an error (like dividing by zero) — See examples below:

False and 12/0 
# Evaluates to False
# Evaluating 12/0 results in an error but because AND operation ends once left operand evaluates to False, 12/0 doesn't get evaluated
True and 12/0
# Results in an error because the left operand is True and so Python evaluates the right operand which throws an error
True or 12/0
# Evaluates to True although 12/0 results in an error
# Because OR operation ends once left operand evaluates to True and then Python gives us the value of the left operand without evaluating right operand
False or 12/0
# Results in an error because the left operand is False and so Python evaluates the right operand which throws an error
If short-circuit evaluation occurs, the operation is complete after just evaluating the left operand (credits: undraw.co)

Short-circuit evaluation is very useful in a number of use cases such as those below:

Toggle feature flags

Feature flags refer to code that can toggle features of our application on or off easily. They are powerful tools to use in software development because they offer a number of key features like:

  • allowing new features to be developed in the main codebase without destabilising existing features
  • turning on new features only for a selected group of users like colleagues or users undergoing A/B testing or small group of user base (to make sure everything runs smoothly before releasing to all users)

To find out more about feature flags and their implementation, visit this excellent post by Mr Martin Fowler.

AND and OR operators are useful in feature flags because they allow us to check multiple conditions that involves consecutive steps where we want to stop evaluating further once one step gives us False. (eg. user has to log in first — server sends back user information and then we can check if user is an admin)

if user.isLoggedIn and user.isAdmin:
then run code to activate feature X
# The AND operator first evaluates the left operand and give us False if user is not logged in (isLoggedIn == False)# But if the user is logged in (isLoggedIn == True), then Python looks at the right operand to check user.isAdmin's boolean value# Only if user.admin is True or evaluate to True, the AND operation gives us True and then the code to activate feature X will run# below is another example using both AND and OR operatorsif user.isEmployee or user.isBetaTester:
then run code to activate feature X
Among other noteworthy points, feature flagging allow developers to work separately on the main codebase (credits: undraw.co)

set default values

Default values for optional function arguments

Imagine that you have designed a super customisable shirt making machine. Your customers can customise various aspects of their shirts like the size, colour, material etc. And so, your machine’s shirt making function requires you to tell it all of those data values.

Sure it is really cool to offer super customisation, but what if your customer just wants to order a “normal” shirt and only change its colour? Remember that your shirt making function expects to be provided with other data values as well.

If you omit an optional argument in a function call, then Python substitutes the default value for that argument — so you can just supply your shirt making function with a customer-chosen colour and the shirt making function can still go on with its job because the other required data values have been filled in by default values.

Note: We can specify more than one optional argument in a function, but all of the optional arguments must follow all of the mandatory arguments.

Default values against undefined variables

In our code, we will frequently encounter situations with undefined variables which may cause our programs to crash. There are many causes, some of which are the following:

  • relying on data retrieved from the internet but Python tries to access it before it is retrieved
  • data created dynamically — which means the data isn’t stored in the program initially but gets stored only based on user action — Python may try to access this data before user has acted to create it

One example of creating data dynamically would be adding dictionary entries. But if Python tries to access an entry that isn’t in the dictionary (ie. key does not exist in the dictionary) then Python will throw a KeyError — causing the program to crash. This problem can be addressed by something called a defaultdict.

Usage of the OR operator in setting default values

The OR operator is suited to setting default values because only if its left operand evaluate to False does Python evaluate its right operand — therefore we can park our default values at the right operand position.

colour = customer-supplied-colour or "white"
# If customer doesn't supply any color data value (it evaluates to False), then the or operation gives us back "white" as the value of the colour variable

For more information on default values for optional argument in Python functions, visit this stackoverflow post!

Default values let us automatically populate optional arguments and guard against undefined values (credits: undraw.co)

Combining Relational and Logical Operators

Special note on combining relational and logical operators because of their usefulness in application logic.

Recall from above that one of the key features of AND and OR operators is its ability to give us True or False after if its operands are all boolean values.

Operations that result in boolean values help us to structure application logic because we can run different pieces of code based on different conditions being met. The AND and OR operators let us build more “complex” conditions off “simpler” relational operations.

To support the combination of relational operators and AND/OR operators, relational operations get evaluated before logical operations. (See order of precedence of operators).

Note: within logical operators, NOT enjoy the highest order of precedence followed by AND and lastly OR.

References

Summary

  • AND and OR logical operators help to build more complex Boolean operations from simpler Boolean operations
  • AND and OR logical operators can also give us operand values when one or both operands are not evaluated to boolean values
  • AND and OR operators support short-circuit evaluation
  • short-circuit evaluation is useful in situations like toggling feature flags and setting default values

Quiz

Which of the following options are accurate about logical operators?

a) 6 > 3 and 3 > 6 gives us False

b) “hello” or “world” gives us “world”

c) not False and True gives us True

d) The AND operator is used to set default values

Quiz explanation

a) Relational operations get evaluated ahead of logical operations. First we evaluate the left operand 6 > 3 which gives us True. Since left operand evaluates to True, Python would evaluate the right operand 3 > 6 which gives us False. Finally, we evaluate the AND operation → True and False gives us False

b) The left operand “hello” has a boolean value of True which triggers short-circuit evaluation in OR operation, giving us “hello”

c) The NOT operator has higher order of precedence than the AND operator so we evaluate not False first. not False gets evaluated to True. Then, True and True evaluates to True

d) The OR operator is much more commonly used in setting default values because it can house the default value in its right operand and set a variable to the default value only if the left operand evaluates to False

Quiz answers: a & c

--

--