Logic

Jon Reades

“The good news about computers is that they do what you tell them to do. The bad news is that they do what you tell them to do.” - Ted Nelson

Do You Want?

Consider the following three things I’ve said to my toddler:

  1. Do you want to go to the park and have ice cream?
  2. Do you want cereal or toast for breakfast?
  3. Do not touch that again or else!

Unlike my toddler, the computer does listen, but my toddler has more common sense!

In Code Now

(x,y) = True,False
if x:
  print("x")

if x and y:
  print("x and y")

if x or y:
  print("x or y")

if x and not y:
  print("x and not y")

if not(x and y):
  print("not x and y")

Combining Logic With Operators

Remember that operators like <= and == also produce True/False answers:

x = y = 5
z = 3
if x==y:
  print("x==y")

if x==y and x==z:
  print("x==y and x==z")

if x==y or x==z:
  print("x==y or x==z")

if x==y and not x==z:
  print("x==y and not x==z")

A Special Case

There is a second set of logical operators that apply in very specific circumstances. These are called ‘bitwise’ operators and apply to data specified in bits.

Regular Operator Bitwise Equivalent
and &
or |
not ~

Let’s see (briefly) how these work…

Working With Bits

x,y = 38,3
print(f"{x:b}") # `:b` means byte-format
print(f"{y:b}")

This gives us that x is '100110' and y is '11', so now:

print(f"{x & y:b}")  # 10
print(f"{x | y:b}")  # 100111
print(f"{x & ~y:b}") # 100100

Perhaps Easier to See This Way?

Operator 1 2 3 4 5 6
x 1 0 0 1 1 0
y 0 0 0 0 1 1
x & y 0 0 0 0 1 0
x | y 1 0 0 1 1 1
~y 1 1 1 1 0 0
x & ~y 1 0 0 1 0 0

Bitwise operations are very, very fast and so are a good way to, say, find things in large data sets. You’ve been warned.

Nulls: None vs. NaN

Beware of using logic with things that are not what they appear:

  • None is Python’s way of saying that something has no value at all (not 0 or ""… but None). It is a class.
  • NaN (Not a Number) is a special numeric data type provided by the numpy package to deal with things like -ve and +ve infinity and similar ‘issues’.

np.nan should be used whenever you are dealing with data (e.g. see Pandas!).

None vs. NaN

import numpy as np
print(type(np.nan))     # float
print(type(None))       # NoneType

Critically:

print(""==None)         # False
print(None==None)       # True
print(np.nan==None)     # False
print(np.nan==np.nan)   # False!
print(np.nan is np.nan) # True
print(np.isnan(np.nan)) # True

Membership

In / Not In

We’ve touched on these before:

g = ['Harvey','Rose','Batty','Jefferson']

if 'Batty' in g:
  print("In the group!")

if 'Marx' not in g:
  print("Not in the group!")

The set data type also supports in, and not in together with all of the set maths (union, intersect, etc.).

Sets

Membership maths:

s1 = {'cherry','orange','banana','tomato'} # Or s1(...)
s2 = {'potato','celery','carrot','tomato'} # Or s2(...)
print('potato' in s1)      # False
print(s1.difference(s2))   # {'banana', ...}
print(s1.intersection(s2)) # {'tomato'}
print(s1.union(s2))        # {'orange', ...}

Resources