truth table: Binary Operations 2
requirements
preview
These are the tests I have at the end of the chapter
1import src.truth_table
2import unittest
3
4
5class TestBinaryOperations(unittest.TestCase):
6
7 def test_contradiction(self):
8 contradiction = src.truth_table.contradiction
9 self.assertFalse(contradiction(True, True))
10 self.assertFalse(contradiction(True, False))
11 self.assertFalse(contradiction(False, True))
12 self.assertFalse(contradiction(False, False))
13
14 def test_logical_conjunction(self):
15 logical_conjunction = (
16 src.truth_table.logical_conjunction
17 )
18 self.assertTrue(
19 logical_conjunction(True, True)
20 )
21 self.assertFalse(
22 logical_conjunction(True, False)
23 )
24 self.assertFalse(
25 logical_conjunction(False, True)
26 )
27 self.assertFalse(
28 logical_conjunction(False, False)
29 )
30
31 def test_project_second(self):
32 project_second = src.truth_table.project_second
33 self.assertTrue(project_second(True, True))
34 self.assertFalse(project_second(True, False))
35 self.assertTrue(project_second(False, True))
36 self.assertFalse(project_second(False, False))
37
38 def test_converse_non_implication(self):
39 converse_non_implication = (
40 src.truth_table.converse_non_implication
41 )
42 self.assertFalse(
43 converse_non_implication(True, True)
44 )
45 self.assertFalse(
46 converse_non_implication(True, False)
47 )
48 self.assertTrue(
49 converse_non_implication(False, True)
50 )
51 self.assertFalse(
52 converse_non_implication(False, False)
53 )
54
55 def test_negate_first(self):
56 negate_first = src.truth_table.negate_first
57 self.assertFalse(negate_first(True, True))
58 self.assertFalse(negate_first(True, False))
59 self.assertTrue(negate_first(False, True))
60 self.assertTrue(negate_first(False, False))
61
62 def test_logical_nand(self):
63 logical_nand = src.truth_table.logical_nand
64 self.assertFalse(logical_nand(True, True))
65 self.assertTrue(logical_nand(True, False))
66 self.assertTrue(logical_nand(False, True))
67 self.assertTrue(logical_nand(False, False))
68
69 def test_tautology(self):
70 tautology = src.truth_table.tautology
71 self.assertTrue(tautology(True, True))
72 self.assertTrue(tautology(True, False))
73 self.assertTrue(tautology(False, True))
74 self.assertTrue(tautology(False, False))
75
76 def test_logical_disjunction(self):
77 logical_disjunction = (
78 src.truth_table.logical_disjunction
79 )
80 self.assertTrue(logical_disjunction(True, True))
81 self.assertTrue(logical_disjunction(True, False))
82 self.assertTrue(logical_disjunction(False, True))
83 self.assertFalse(logical_disjunction(False, False))
84
85
86# Exceptions seen
87# AttributeError
88# TypeError
89# AssertionError
90# SyntaxError
continue the project
Make sure you are in the
pumping_pythonfolder with pwd in the terminalpwdif the terminal does not show
.../pumping_pythonchange directory to the
pumping_pythonfolderOnce in
pumping_python, change directory to the projectcd truth_tablethe terminal shows
.../pumping_python/truth_tableI run the tests with pytest-watcher
uv run pytest-watcher . --nowthe terminal is my friend, and shows
rootdir: .../pumping_python/truth_table configfile: pyproject.toml collected 8 items tests/test_binary.py .... [ 50%] tests/test_nullary_unary.py .... [100%] ================== 8 passed in G.HIs ===================I hold ctrl (Windows) or option (MacOS) on the keyboard, then click on
tests/test_binary.pywith the mouse to open itSo far I have tested
contradiction which always returns False
logical_conjunction aka and which returns
first_input and second_inputproject_second which always returns
second_inputconverse_non_implication which returns
not first_input and second_input
test_negate_first
The truth table for negate_first is
first input |
second input |
return |
|---|---|---|
True |
True |
False |
True |
False |
False |
False |
True |
True |
False |
False |
True |
RED: make it fail
I add a test for negate_first with an assertion for when the first input is True and the second input is True, to test_binary.py
first input |
second input |
return |
|---|---|---|
True |
False |
False |
38 def test_converse_non_implication(self):
39 converse_non_implication = (
40 src.truth_table.converse_non_implication
41 )
42 self.assertFalse(
43 converse_non_implication(True, True)
44 )
45 self.assertFalse(
46 converse_non_implication(True, False)
47 )
48 self.assertTrue(
49 converse_non_implication(False, True)
50 )
51 self.assertFalse(
52 converse_non_implication(False, False)
53 )
54
55 def test_negate_first(self):
56 negate_first = src.truth_table.negate_first
57 self.assertFalse(negate_first(True, True))
58
59
60 # Exceptions seen
the terminal is my friend, and shows AttributeError
AttributeError: module 'src.truth_table'
has no attribute 'negate_first'
there is no definition for negate_first in truth_table.py
GREEN: make it pass
I open
truth_table.pyfrom thesrcfolderI add the function to
truth_table.py29def converse_non_implication(first_input, second_input): 30 return logical_conjunction( 31 logical_negation(first_input), 32 second_input 33 ) 34 return not first_input and second_input 35 36 37def negate_first(first_input, second_input): 38 return Falsethe test passes. negate_first returns False, if the first input is True and the second input is True.
REFACTOR: make it better
I add an assertion for the second case, which is when the first input is True and the second input is False, to test_negate_first in
test_binary.pyfirst input
second input
return
True
False
False
55 def test_negate_first(self): 56 negate_first = src.truth_table.negate_first 57 self.assertFalse(negate_first(True, True)) 58 self.assertFalse(negate_first(True, False)) 59 60 61# Exceptions seenthe test is still green. negate_first returns
False, if the first input is True and the second input is False
False, if the first input is True and the second input is True
False, if the first input is True
I add an assertion for the next case, which is when the first input is False and the second input is True
first input
second input
return
False
True
True
55 def test_negate_first(self): 56 negate_first = src.truth_table.negate_first 57 self.assertFalse(negate_first(True, True)) 58 self.assertFalse(negate_first(True, False)) 59 self.assertTrue(negate_first(False, True)) 60 61 62# Exceptions seenthe terminal is my friend, and shows AssertionError
AssertionError: False is not truebecause the negate_first function returns False and the assertion expects True.
I add an if statement for this case to negate_first in
truth_table.py37def negate_first(first_input, second_input): 38 if first_input == False: 39 return True 40 return Falsethe test passes. negate_first returns
True, if the first input is False
False, if the above condition is not met
I add an assertion for the last case, which is when the first input is False and the second input is False to test_negate_first in
test_binary.pyfirst input
second input
return
False
False
True
55 def test_negate_first(self): 56 negate_first = src.truth_table.negate_first 57 self.assertFalse(negate_first(True, True)) 58 self.assertFalse(negate_first(True, False)) 59 self.assertTrue(negate_first(False, True)) 60 self.assertTrue(negate_first(False, False)) 61 62 63# Exceptions seenthe test is still green because this happens when
if first_input == False:runs, Python checks iffirst_inputis equal to Falseif
first_inputis NOT equal to False, it leaves the if statement and continues to run the rest of the function -return Falseand leaves the function since the return statement is the last thing to run in a functionif
first_inputis equal to False, it goes to the next line - ``return True `` and leaves the function since the return statement is the last thing to run in a function
I add the bool built-in function to the if statement in the negate_first function in
truth_table.py37def negate_first(first_input, second_input): 38 # if first_input == False: 39 if bool(first_input) == False: 40 return True 41 return Falsestill green.
I use Logical Negation (NOT) to write it in terms of True
37def negate_first(first_input, second_input): 38 # if first_input == False: 39 # if bool(first_input) == False: 40 if bool(not first_input) == True: 41 return True 42 return Falsegreen.
I remove
== True37def negate_first(first_input, second_input): 38 # if first_input == False: 39 # if bool(first_input) == False: 40 # if bool(not first_input) == True: 41 if bool(not first_input): 42 return True 43 return Falsestill green.
I remove bool
37def negate_first(first_input, second_input): 38 # if first_input == False: 39 # if bool(first_input) == False: 40 # if bool(not first_input) == True: 41 # if bool(not first_input): 42 if not first_input: 43 return True 44 return Falsethe test is still green because when
if first_input == False:runs, Python checks iffirst_inputis equal to False. I can assume the following substitutionsif the value of
somethingis Falseif something == False if bool(something ) == False if bool(False ) == False if False == False if True == True # use equality if True # remove '== True' if not False # change to terms of False if not somethingif the value of
somethingis Trueif something == False if bool(something ) == False if bool(True ) == False if True == False if False == True # use equality if False # remove '== True' if not True # change to terms of True if not something
if bool(something) == Falseis the same asif bool(not something) == Trueis the same asif bool(not something)is the same asif not something.I add an else clause to be clearer
37def negate_first(first_input, second_input): 38 # if first_input == False: 39 # if bool(first_input) == False: 40 # if bool(not first_input) == True: 41 # if bool(not first_input): 42 if not first_input: 43 return True 44 else: 45 return Falsestill green.
I use a conditional expression (ternary operator) for the if statements
37def negate_first(first_input, second_input): 38 # if first_input == False: 39 # if bool(first_input) == False: 40 # if bool(not first_input) == True: 41 # if bool(not first_input): 42 # if not first_input: 43 # return True 44 # else: 45 # return False 46 return True if not first_input else Falsestill green.
I remove
True ifandelse False37def negate_first(first_input, second_input): 38 # if first_input == False: 39 # if bool(first_input) == False: 40 # if bool(not first_input) == True: 41 # if bool(not first_input): 42 # if not first_input: 43 # return True 44 # else: 45 # return False 46 # return True if not first_input else False 47 return not first_inputgreen.
I remove the commented lines
37def negate_first(first_input, second_input): 38 return not first_inputI add a git commit message in another terminal
git commit -am 'add negate_first'
Negate First always returns
not first_inputTrue, if the first input is False
False, if the first input is True
the Logical Negation (NOT) of the first input in all cases, it does not care about the second input
examples of Negate First
approval to do something based on risk and reason, if the inputs are
is it risky?
has a good reason?
is risky?
has reason?
approved
yes
good
no
yes
bad
no
no
good
yes
no
bad
yes
going for a walk, if the inputs are
is it raining?
do I feel like walking?
is raining?
feel like walking?
should walk
yes
yes
no
yes
no
no
no
yes
yes
no
no
yes
smoke detector battery test, if the inputs are
is the battery dead?
is there smoke?
battery dead?
is there smoke?
beep
yes
yes
no
yes
no
no
no
yes
yes
no
no
yes
can the system be used while it is being updated, if the inputs are
is update running?
is user admin?
update running?
admin?
system can be used
yes
yes
no
yes
no
no
no
yes
yes
no
no
yes
test_logical_nand
The truth table for logical_nand is
first input |
second input |
return |
|---|---|---|
True |
True |
False |
True |
False |
True |
False |
True |
True |
False |
False |
True |
RED: make it fail
I go back to the terminal where the tests are running
I add a test for logical_nand with an assertion for when the first input is True and the second input is True, to
test_binary.pyfirst input
second input
return
True
True
False
55 def test_negate_first(self): 56 negate_first = src.truth_table.negate_first 57 self.assertFalse(negate_first(True, True)) 58 self.assertFalse(negate_first(True, False)) 59 self.assertTrue(negate_first(False, True)) 60 self.assertTrue(negate_first(False, False)) 61 62 def test_logical_nand(self): 63 logical_nand = src.truth_table.logical_nand 64 self.assertFalse(logical_nand(True, True)) 65 66 67# Exceptions seenthe terminal is my friend, and shows AttributeError
AttributeError: module 'src.truth_table' has no attribute 'logical_nand'. Did you mean: 'logical_false'?because there is no definition for logical_nand in
truth_table.py
GREEN: make it pass
I add the function to truth_table.py
37def negate_first(first_input, second_input):
38 return not first_input
39
40
41def logical_nand(first_input, second_input):
42 return False
the test passes. logical_nand returns False, if the first input is True and the second input is True.
REFACTOR: make it better
I add an assertion for the second case, which is when the first input is True and the second input is False, to test_logical_nand in
test_binary.pyfirst input
second input
return
True
False
True
62 def test_logical_nand(self): 63 logical_nand = src.truth_table.logical_nand 64 self.assertFalse(logical_nand(True, True)) 65 self.assertTrue(logical_nand(True, False)) 66 67 68# Exceptions seenthe terminal is my friend, and shows AssertionError
AssertionError: False is not truebecause the function returns False and the assertion expects True.
I add an if statement to the logical_nand function in
truth_table.py41def logical_nand(first_input, second_input): 42 if second_input == False: 43 return True 44 return Falsethe test passes. logical_nand returns
True, if the second input is False
False, if the above condition is NOT met
the logical negation of the second input so far
I add another assertion, for the case when the first input is False and the second input is True, to test_logical_nand in
test_binary.pyfirst input
second input
return
False
True
True
62 def test_logical_nand(self): 63 logical_nand = src.truth_table.logical_nand 64 self.assertFalse(logical_nand(True, True)) 65 self.assertTrue(logical_nand(True, False)) 66 self.assertTrue(logical_nand(False, True)) 67 68 69# Exceptions seenthe terminal is my friend, and shows AssertionError
AssertionError: False is not truebecause this happens when
if second_input == False:runs, Python checks ifsecond_inputis equal to Falseif
second_inputis NOT equal to False, it leaves the if statement and continues to run the rest of the function -return Falseand leaves the function since the return statement is the last thing to run in a functionif
second_inputis equal to False, it goes to the next line - ``return True `` and leaves the function since the return statement is the last thing to run in a functionsecond_inputis True in this case, which raises AssertionError since the function returns False and the assertion expects True
I add an if statement to the logical_nand function in
truth_table.py41def logical_nand(first_input, second_input): 42 if first_input == False: 43 return True 44 if second_input == False: 45 return True 46 return Falsethe test passes. logical_nand returns
True, if the first input is False
True, if the second input is False
False, if none of the above conditions are met
I add an assertion for the last case, which is when the first input is False and the second input is False, to test_logical_nand in
test_binary.pyfirst input
second input
return
False
False
True
62 def test_logical_nand(self): 63 logical_nand = src.truth_table.logical_nand 64 self.assertFalse(logical_nand(True, True)) 65 self.assertTrue(logical_nand(True, False)) 66 self.assertTrue(logical_nand(False, True)) 67 self.assertTrue(logical_nand(False, False)) 68 69 70# Exceptions seenthe test is still green because this happens when logical_nand is called - it runs
if first_input == False:, where Python checks iffirst_inputis equal to Falseif
first_inputis equal to False, it goes to the next line - ``return True `` and leaves the function since the return statement is the last thing to run in a functionif
first_inputis NOT equal to False, it leaves the if statement and continues to the next if statement in the function -if second_input == False:which checks ifsecond_inputis equal to Falseif
second_inputis NOT equal to False, it leaves the if statement and continues to run the rest of the function -return Falseand leaves the function since the return statement is the last thing to run in a functionif
second_inputis equal to False, it goes to the next line - ``return True `` and leaves the function since the return statement is the last thing to run in a function
There is only one case where logical_nand returns False (the first case, when the first input is True and the second input is True). I add if statements for it, in
truth_table.py41def logical_nand(first_input, second_input): 42 # if first_input == False: 43 # return True 44 # if second_input == False: 45 # return True 46 # return False 47 if first_input == True: 48 if second_input == True: 49 return False 50 return Truestill green because logical_nand returns
False if the first input is True and the second input is True
True if the above condition is NOT met
this happens when
if first_input == True:runs, Python checks iffirst_inputis equal to Trueif
first_inputis NOT equal to True, it leaves the if statement and continues to run the rest of the function - ``return True `` and leaves the function since the return statement is the last thing to run in a functionif
first_inputis equal to True, it goes to the next if statement -if second_input == True, which checks ifsecond_inputis equal to Trueif
second_inputis NOT equal to True, it leaves the if statement and continues to run the rest of the function - ``return True `` and leaves the function since the return statement is the last thing to run in a functionif
second_inputis equal to True, it goes to the next line -return Falseand leaves the function since the return statement is the last thing to run in a function
I use the bool built-in function
41def logical_nand(first_input, second_input): 42 # if first_input == False: 43 # return True 44 # if second_input == False: 45 # return True 46 # return False 47 # if first_input == True: 48 if bool(first_input) == True: 49 # if second_input == True: 50 if bool(second_input) == True: 51 return False 52 return Truegreen.
I remove
== True41def logical_nand(first_input, second_input): 42 # if first_input == False: 43 # return True 44 # if second_input == False: 45 # return True 46 # return False 47 # if first_input == True: 48 # if bool(first_input) == True: 49 if bool(first_input): 50 # if second_input == True: 51 # if bool(second_input) == True: 52 if bool(second_input): 53 return False 54 return Truestill green.
I remove bool
41def logical_nand(first_input, second_input): 42 # if first_input == False: 43 # return True 44 # if second_input == False: 45 # return True 46 # return False 47 # if first_input == True: 48 # if bool(first_input) == True: 49 # if bool(first_input): 50 if first_input: 51 # if second_input == True: 52 # if bool(second_input) == True: 53 # if bool(second_input): 54 if second_input: 55 return False 56 return Truethe test is still green, because I can assume the following substitutions for
if something == True:if the value of
somethingis Falseif something == True if bool(something ) == True if bool(False ) == True if False == True if not True == True # change to terms of True if not True # remove '==True' if False if somethingif the value of
somethingis Trueif something == True if bool(something ) == True if bool(True ) == True if True == True # remove '==True' if True if something
if bool(something) == Trueis the same asif bool(something)is the same asif something.I use Logical Conjunction (AND) to put the two if statements together
41def logical_nand(first_input, second_input): 42 # if first_input == False: 43 # return True 44 # if second_input == False: 45 # return True 46 # return False 47 # if first_input == True: 48 # if bool(first_input) == True: 49 # if bool(first_input): 50 # if first_input: 51 # if second_input == True: 52 # if bool(second_input) == True: 53 # if bool(second_input): 54 # if second_input: 55 if first_input and second_input: 56 return False 57 return Truestill green, because I can put two if statements together when one is indented under the other
if something: if something_else:can also be written as
if something and something_else:I add an else clause to make it clearer
41def logical_nand(first_input, second_input): 42 # if first_input == False: 43 # return True 44 # if second_input == False: 45 # return True 46 # return False 47 # if first_input == True: 48 # if bool(first_input) == True: 49 # if bool(first_input): 50 # if first_input: 51 # if second_input == True: 52 # if bool(second_input) == True: 53 # if bool(second_input): 54 # if second_input: 55 if first_input and second_input: 56 return False 57 else: 58 return Truegreen.
I rewrite the else clause with the Logical Negation (NOT) of
first_input and second_inputso I can write the statements with a conditional expression (ternary operator)55def logical_nand(first_input, second_input): 56 # if first_input == False: 57 # return True 58 # if second_input == False: 59 # return True 60 # return False 61 # if first_input == True: 62 # if bool(first_input) == True: 63 # if bool(first_input): 64 # if first_input: 65 # if second_input == True: 66 # if bool(second_input) == True: 67 # if bool(second_input): 68 # if second_input: 69 if first_input and second_input: 70 return False 71 # else: 72 if not (first_input and second_input): 73 return Truestill green.
I move the first if statement below this new one
41def logical_nand(first_input, second_input): 42 # if first_input == False: 43 # return True 44 # if second_input == False: 45 # return True 46 # return False 47 # if first_input == True: 48 # if bool(first_input) == True: 49 # if bool(first_input): 50 # if first_input: 51 # if second_input == True: 52 # if bool(second_input) == True: 53 # if bool(second_input): 54 # if second_input: 55 # else: 56 if not (first_input and second_input): 57 return True 58 if first_input and second_input: 59 return Falsethe test is still green.
I change
if first_input and second_inputto an else clause55def logical_nand(first_input, second_input): 56 # if first_input == False: 57 # return True 58 # if second_input == False: 59 # return True 60 # return False 61 # if first_input == True: 62 # if bool(first_input) == True: 63 # if bool(first_input): 64 # if first_input: 65 # if second_input == True: 66 # if bool(second_input) == True: 67 # if bool(second_input): 68 # if second_input: 69 # else: 70 if not (first_input and second_input): 71 return True 72 # if first_input and second_input: 73 else: 74 return Falsestill green.
I add a conditional expression
55 # else: 56 # if not (first_input and second_input): 57 # return True 58 # if first_input and second_input: 59 # else: 60 # return False 61 return ( 62 True if 63 not (first_input and second_input) 64 else False 65 )green.
I remove
True ifandelse Falseto make the statement simpler55 # else: 56 # if not (first_input and second_input): 57 # return True 58 # if first_input and second_input: 59 # else: 60 # return False 61 return ( 62 # True if 63 not (first_input and second_input) 64 # else False 65 )still green because when there is only one if statement that returns False with an else clause
if something: return False else: return Truesince
elseis the logical_negation (not) of the if statementif something: return False if not something: return TrueI can use its logical negation (not) to return True
if not something: return True else: return FalseI can then write it with a ternary operator (conditional expression)
return True if not (something) else Falsewhich can be made simpler as
return not (something)this means
if something: return Falseis the same asreturn not (something)since Python groups objects as False or Truelogical_nand returns
not (first_input and second_input)which is the Logical Negation (NOT) of the Logical Conjunction (AND) of the first input and second input, which means that in the four casesif the first input is True and the second input is True, logical_nand returns
not (first and second) not (True and True) not (True) # not logical_conjunction(True, True) Falseif the first input is True and the second input is False, logical_nand returns
not (first and second) not (True and False) not (False) # not logical_conjunction(True, False) Trueif the first input is False and the second input is True, logical_nand returns
not (first and second) not (False and True) not (False) # not logical_conjunction(False, True) Trueif the first input is False and the second input is False, logical_nand returns
not (first and second) not (False and False) not (False) # not logical_conjunction(False, False) True
first
second
first and second
not (first and second)
True
True
True
False
True
False
False
True
False
True
False
True
False
False
False
True
I add a return statement to show this
55 # else: 56 # if not (first_input and second_input): 57 # return True 58 # if first_input and second_input: 59 # else: 60 # return 61 return logical_negation( 62 logical_conjunction( 63 first_input, second_input 64 ) 65 ) 66 return ( 67 # True if 68 not (first_input and second_input) 69 # else False 70 )the test is still green.
I remove the comments
41def logical_nand(first_input, second_input): 42 return logical_negation( 43 logical_conjunction( 44 first_input, second_input 45 ) 46 ) 47 return not (first_input and second_input)I can use any of these two `return statements`_, the first return statement is the only one that runs in this case, because the return statement is the last thing to run in a function.
I add a git commit message in the other terminal
git commit -am 'add logical_nand'
returns False, if the first input is True and the second input is True
returns
not (first_input and second_input)which is the Logical Negation (NOT) of the Logical Conjunction (AND) of the first input and the second input, many wordsis the Logical Negation (NOT) of Logical Conjunction (AND) which only returns True, if the first input is True and the second input is True
is the not of the and of the first input and second input, confusing?
is not and
examples of Logical NAND
can the website be reached, if the inputs are
is main server down?
is backup server down?
is main down?
is backup down?
can reach website?
yes
yes
no
yes
no
yes
no
yes
yes
no
no
yes
safety when mixing household cleaning products, if the inputs are
is bleach?
is soap?
is bleach?
is soap?
is safe when mixed?
yes
yes
no
yes
no
yes
no
yes
yes
no
no
yes
fridge alarm, if the inputs are
door open?
temperature rose?
door open?
temperature rose?
silent
yes
yes
no
yes
no
yes
no
yes
yes
no
no
yes
approve a transaction, if the inputs are
amount is larger than normal?
the recipient is new?
large amount?
new recipient?
approve?
yes
yes
no
yes
no
yes
no
yes
yes
no
no
yes
show content, if the inputs are
is user younger than 18?
is the content flagged as adult?
less than 18?
adult content?
show content
yes
yes
no
yes
no
yes
no
yes
yes
no
no
yes
allow 2 processes writing to the same place, if the inputs are
is process A writing?
is process B writing?
process A write?
process B write?
allow?
yes
yes
no
yes
no
yes
no
yes
yes
no
no
yes
test_tautology
The truth table for tautology is
first input |
second input |
return |
|---|---|---|
True |
True |
True |
True |
False |
True |
False |
True |
True |
False |
False |
True |
RED: make it fail
I go back to the terminal where the tests are running
I add a test for tautology with an assertion for when the first input is True and the second input is True, to
test_binary.pyfirst input
second input
return
True
True
True
62 def test_logical_nand(self): 63 logical_nand = src.truth_table.logical_nand 64 self.assertFalse(logical_nand(True, True)) 65 self.assertTrue(logical_nand(True, False)) 66 self.assertTrue(logical_nand(False, True)) 67 self.assertTrue(logical_nand(False, False)) 68 69 def test_tautology(self): 70 tautology = src.truth_table.tautology 71 self.assertTrue(tautology(True, True)) 72 73 74# Exceptions seenthe terminal is my friend, and shows AttributeError
AttributeError: module 'src.truth_table' has no attribute 'tautology'truth_table.pydoes not have tautology in it.
GREEN: make it pass
I add the function to truth_table.py
41 def logical_nand(first_input, second_input):
42 return logical_negation(
43 logical_conjunction(
44 first_input, second_input
45 )
46 )
47 return not (first_input and second_input)
48
49
50 def tautology(first_input, second_input):
51 return True
the test passes. tautology returns True, if the first input is True and the second input is True.
REFACTOR: make it better
I add an assertion for the next case, which is when the first input is True and the second input is False, to test_tautology in
test_binary.pyfirst input
second input
return
True
False
True
69 def test_tautology(self): 70 tautology = src.truth_table.tautology 71 self.assertTrue(tautology(True, True)) 72 self.assertTrue(tautology(True, False)) 73 74 75# Exceptions seenthe test is still green. tautology returns
True, if the first input is True and the second input is False
True, if the first input is True and the second input is True
True, if the first input is True
I add an assertion for the next case, which is when the first input is False and the second input is True
first input
second input
return
False
True
True
69 def test_tautology(self): 70 tautology = src.truth_table.tautology 71 self.assertTrue(tautology(True, True)) 72 self.assertTrue(tautology(True, False)) 73 self.assertTrue(tautology(False, True)) 74 75 76# Exceptions seenthe test is still green. tautology returns True
if the first input is False and the second input is True
if the first input is True
I add an assertion for the last case, which is when the first input is False and the second input is False
first input
second input
return
False
False
True
69 def test_tautology(self): 70 tautology = src.truth_table.tautology 71 self.assertTrue(tautology(True, True)) 72 self.assertTrue(tautology(True, False)) 73 self.assertTrue(tautology(False, True)) 74 self.assertTrue(tautology(False, False)) 75 76 77# Exceptions seenstill green, there is only one result for this operation.
I add a git commit message in the other terminal
git commit -am 'add tautology'
Tautology always returns True, it does not care about the inputs. It is the opposite of contradiction which always returns False.
examples of Tautology
work, if the inputs are
do I have work?
do I feel like working?
have work?
feel like work?
work?
yes
yes
yes
yes
no
yes
no
yes
yes
no
no
yes
the customer is always right, if the inputs are
did customer complain?
is customer new?
complain?
new?
is customer king?
yes
yes
yes
yes
no
yes
no
yes
yes
no
no
yes
the sun is real, if the inputs are
am I awake?
is it bright or dark outside?
awake?
bright/dark?
is sun real?
yes
bright
yes
yes
dark
yes
no
bright
yes
no
dark
yes
I can get better, if the inputs are
am I good?
have I done this before?
good?
done before?
can I get better?
yes
yes
yes
yes
no
yes
no
yes
yes
no
no
yes
a noun is the name of a person, place or thing, if the inputs are
is a person?
is a place or a thing?
person?
place/thing?
noun is a name
yes
place
yes
yes
thing
yes
no
place
yes
no
thing
yes
unconditional love, if the inputs are
has the person been good?
does the person deserve love?
been good?
deserving?
love?
yes
yes
yes
yes
no
yes
no
yes
yes
no
no
yes
test_logical_disjunction
The truth table for logical_disjunction is
first input |
second input |
return |
|---|---|---|
True |
True |
True |
True |
False |
True |
False |
True |
True |
False |
False |
False |
RED: make it fail
I go back to the terminal where the tests are running
I add a test for logical_disjunction with an assertion for when the first input is True and the second input is True, to
test_binary.pyfirst input
second input
return
True
True
True
69 def test_tautology(self): 70 tautology = src.truth_table.tautology 71 self.assertTrue(tautology(True, True)) 72 self.assertTrue(tautology(True, False)) 73 self.assertTrue(tautology(False, True)) 74 self.assertTrue(tautology(False, False)) 75 76 def test_logical_disjunction(self): 77 logical_disjunction = ( 78 src.truth_table.logical_disjunction 79 ) 80 self.assertTrue(logical_disjunction(True, True)) 81 82 83# Exceptions seenthe terminal is my friend, and shows AttributeError
AttributeError: module 'src.truth_table' has no attribute 'logical_disjunction'. Did you mean: 'logical_conjunction'?there is no logical_disjunction in
truth_table.pyin thesrcfolder, yet.
GREEN: make it pass
I add the function to truth_table.py
50def tautology(first_input, second_input):
51 return True
52
53
54def logical_disjunction(first_input, second_input):
55 return True
the test passes. logical_disjunction returns True, if the first input is True and the second input is True.
REFACTOR: make it better
I add an assertion for the next case, which is when the first input is True and the second input is False, to test_logical_disjunction in
test_binary.pyfirst input
second input
return
True
False
True
76 def test_logical_disjunction(self): 77 logical_disjunction = ( 78 src.truth_table.logical_disjunction 79 ) 80 self.assertTrue(logical_disjunction(True, True)) 81 self.assertTrue(logical_disjunction(True, False)) 82 83 84# Exceptions seenthe test is still green. logical_disjunction returns
True, if the first input is True and the second input is False
True, if the first input is True and the second input is True
True, if the first input is True
so far this is the same as tautology.
I add an assertion for the next case, which is when the first input is False and the second input is True
first input
second input
return
False
True
True
76 def test_logical_disjunction(self): 77 logical_disjunction = ( 78 src.truth_table.logical_disjunction 79 ) 80 self.assertTrue(logical_disjunction(True, True)) 81 self.assertTrue(logical_disjunction(True, False)) 82 self.assertTrue(logical_disjunction(False, True)) 83 84 85# Exceptions seenthe test is still green. logical_disjunction still looks like Tautology, it returns
True, if the first input is False and the second input is True
True, if the first input is True
I add an assertion for the fourth case, which is when the first input is False and the second input is False
first input
second input
return
False
False
False
76 def test_logical_disjunction(self): 77 logical_disjunction = ( 78 src.truth_table.logical_disjunction 79 ) 80 self.assertTrue(logical_disjunction(True, True)) 81 self.assertTrue(logical_disjunction(True, False)) 82 self.assertTrue(logical_disjunction(False, True)) 83 self.assertFalse(logical_disjunction(False, False)) 84 85 86# Exceptions seenthe terminal is my friend, and shows AssertionError
AssertionError: True is not falsebecause the logical_disjunction function returns True and this assertion expects False.
I add if statements for the new case to logical_disjunction in
truth_table.py54def logical_disjunction(first_input, second_input): 55 if first_input == False: 56 if second_input == False: 57 return False 58 return Truethe test passes happens when
if first_input == False:runs, Python checks iffirst_inputis equal to Falseif
first_inputis NOT equal to False, it leaves the if statement and continues to run the rest of the function - ``return True `` and leaves the function since the return statement is the last thing to run in a functionif
first_inputis equal to False, it goes to the next line -if second_input == False:, which checks ifsecond_inputis equal to Falseif
second_inputis NOT equal to False, it leaves the if statement and continues to run the rest of the function - ``return True `` and leaves the function since the return statement is the last thing to run in a functionif
second_inputis equal to False, it goes to the next line -return Falseand leaves the function since the return statement is the last thing to run in a function
I add the bool built-in function
54def logical_disjunction(first_input, second_input): 55 # if first_input == False: 56 if bool(first_input) == False: 57 # if second_input == False: 58 if bool(second_input) == False: 59 return False 60 return Truethe test is still green.
I use Logical Negation (NOT) to write the if statements in terms of True
54def logical_disjunction(first_input, second_input): 55 # if first_input == False: 56 # if bool(first_input) == False: 57 if bool(not first_input) == True: 58 # if second_input == False: 59 # if bool(second_input) == False: 60 if bool(not second_input) == True: 61 return False 62 return Truestill green.
I remove
== True54def logical_disjunction(first_input, second_input): 55 # if first_input == False: 56 # if bool(first_input) == False: 57 # if bool(not first_input) == True: 58 if bool(not first_input): 59 # if second_input == False: 60 # if bool(second_input) == False: 61 # if bool(not second_input) == True: 62 if bool(not second_input): 63 return False 64 return Truegreen.
I remove bool
54def logical_disjunction(first_input, second_input): 55 # if first_input == False: 56 # if bool(first_input) == False: 57 # if bool(not first_input) == True: 58 # if bool(not first_input): 59 if not first_input: 60 # if second_input == False: 61 # if bool(second_input) == False: 62 # if bool(not second_input) == True: 63 # if bool(not second_input): 64 if not second_input: 65 return False 66 return Truestill green because I can assume the following substitutions for
if something == False:if the value of
somethingis Falseif something == False if bool(something ) == False if bool(False ) == False if False == False if True == True # use equality if True # remove '== True' if not False # change to terms of False if not somethingif the value of
somethingis Trueif something == False if bool(something ) == False if bool(True ) == False if True == False if False == True # use equality if False # remove '== True' if not True # change to terms of True if not something
if bool(something) == Falseis the same asif bool(not something) == Trueis the same asif bool(not something)is the same asif not something.I use Logical Conjunction (AND) to put the two if statements together
54def logical_disjunction(first_input, second_input): 55 # if first_input == False: 56 # if bool(first_input) == False: 57 # if bool(not first_input) == True: 58 # if bool(not first_input): 59 # if not first_input: 60 # if second_input == False: 61 # if bool(second_input) == False: 62 # if bool(not second_input) == True: 63 # if bool(not second_input): 64 # if not second_input: 65 if not first_input and not second_input: 66 return False 67 return Truestill green, because I can put two if statements together when one is indented under the other
if something: if something_else:can also be written as
if something and something_else:I add an else clause to make it clearer
54def logical_disjunction(first_input, second_input): 55 # if first_input == False: 56 # if bool(first_input) == False: 57 # if bool(not first_input) == True: 58 # if bool(not first_input): 59 # if not first_input: 60 # if second_input == False: 61 # if bool(second_input) == False: 62 # if bool(not second_input) == True: 63 # if bool(not second_input): 64 # if not second_input: 65 if not first_input and not second_input: 66 return False 67 else: 68 return Truegreen.
I use Logical Negation (NOT) to change the else clause to the opposite of the if statement
65 if not first_input and not second_input: 66 return False 67 # else: 68 if not (not first_input and not second_input): 69 return Truestill green.
I move the first if statement below the new one
54def logical_disjunction(first_input, second_input): 55 # if first_input == False: 56 # if bool(first_input) == False: 57 # if bool(not first_input) == True: 58 # if bool(not first_input): 59 # if not first_input: 60 # if second_input == False: 61 # if bool(second_input) == False: 62 # if bool(not second_input) == True: 63 # if bool(not second_input): 64 # if not second_input: 65 # else: 66 if not (not first_input and not second_input): 67 return True 68 if not first_input and not second_input: 69 return Falsethe test is still green.
I change it to an else clause
54def logical_disjunction(first_input, second_input): 55 # if first_input == False: 56 # if bool(first_input) == False: 57 # if bool(not first_input) == True: 58 # if bool(not first_input): 59 # if not first_input: 60 # if second_input == False: 61 # if bool(second_input) == False: 62 # if bool(not second_input) == True: 63 # if bool(not second_input): 64 # if not second_input: 65 # else: 66 if not (not first_input and not second_input): 67 return True 68 # if not first_input and not second_input: 69 else: 70 return Falsestill green.
I add a conditional expression (ternary operator)
65 # else: 66 # if not (not first_input and not second_input): 67 # return True 68 # if not first_input and not second_input: 69 # else: 70 # return False 71 return ( 72 True if 73 not (not first_input and not second_input) 74 else False 75 )green.
I remove
True ifandelse Falseto make it simpler65 # else: 66 # if not (not first_input and not second_input): 67 # return True 68 # if not first_input and not second_input: 69 # else: 70 # return False 71 return ( 72 # True if 73 not (not first_input and not second_input) 74 # else False 75 )still green.
not happens 3 times in this statement. I “multiply” it by every symbol in the statement to try to make it simpler
65 # else: 66 # if not (not first_input and not second_input): 67 # return True 68 # if not first_input and not second_input: 69 # else: 70 # return False 71 # return ( 72 # True if 73 # not (not first_input and not second_input) 74 # else False 75 # ) 76 return ( 77 (not not first_input) 78 (not and) 79 (not not second_input) 80 )the terminal is my friend and shows SyntaxError
SyntaxError: invalid syntaxI add SyntaxError to the list of Exceptions seen in
test_binary.py86# Exceptions seen 87# AttributeError 88# TypeError 89# AssertionError 90# SyntaxErrorI change
not andtoorin the logical_disjunction function intruth_table.py76 return ( 77 (not not first_input) 78 # (not and) 79 or 80 (not not second_input) 81 )the test is green again
I remove
not notbecause they cancel out76 return ( 77 # (not not first_input) 78 first_input 79 # (not and) 80 or 81 # (not not second_input) 82 second_input 83 )the test is still green. Do two nots make a right?
logical_disjunction returns
not ((not first_input) and (not second_input))which is the Logical Negation (NOT) of the Logical Conjunction of the Logical Negation offirst_input, and the Logical Negation ofsecond_input.logical_negation( logical_conjunction( logical_negation(first_input), logical_negation(second_input) ) )not first_inputis the Logical Negation (NOT) offirst_inputif the first input is True, this part of the statement is False and exits the function
if the first input is False, this part of the statement is True
not second_inputis the Logical Negation (NOT) ofsecond_inputif the second input is True, this part of the statement is False
if the second input is False, this part of the statement is True
This means that in the four cases
if the first input is True and the second input is True, logical_disjunction returns
not ((not first) and (not second)) not ((not True) and (not True) ) not (False and False ) not False # not logical_conjunction(False, False) Trueif the first input is True and the second input is False, logical_disjunction returns
not ((not first) and (not second)) not ((not True) and (not False) ) not (False and True ) not False # not logical_conjunction(False, True) Trueif the first input is False and the second input is True, logical_disjunction returns
not ((not first) and (not second)) not ((not False) and (not True) ) not (True and False ) not False # not logical_conjunction(True, False) Trueif the first input is False and the second input is False, logical_disjunction returns
not ((not first) and (not second)) not ((not False) and (not False) ) not (True and True ) not True # not logical_conjunction(True, True) False
first
second
not first
not second
((not first) and (not second))
not ((not first) and (not second))
True
True
False
False
False
True
True
False
False
True
False
True
False
True
True
False
False
True
False
False
True
True
True
False
I add a return statement to show this
54def logical_disjunction(first_input, second_input): 55 # if first_input == False: 56 # if bool(first_input) == False: 57 # if bool(not first_input) == True: 58 # if bool(not first_input): 59 # if not first_input: 60 # if second_input == False: 61 # if bool(second_input) == False: 62 # if bool(not second_input) == True: 63 # if bool(not second_input): 64 # if not second_input: 65 # else: 66 # if not (not first_input and not second_input): 67 # return True 68 # if not first_input and not second_input: 69 # else: 70 # return False 71 # return ( 72 # True if 73 # not (not first_input and not second_input) 74 # else False 75 # ) 76 return logical_negation( 77 logical_conjunction( 78 logical_negation(first_input), 79 logical_negation(second_input) 80 ) 81 ) 82 return ( 83 # (not not first_input) 84 first_input 85 # (not and) 86 or 87 # (not not second_input) 88 second_input 89 )still green.
I remove the commented lines
54def logical_disjunction(first_input, second_input): 55 return logical_negation( 56 logical_conjunction( 57 logical_negation(first_input), 58 logical_negation(second_input) 59 ) 60 ) 61 return first_input or second_inputI can use any of these two `return statements`_, the first return statement is the only one that runs in this case, because the return statement is the last thing to run in a function.
I add a git commit message in the other terminal
git commit -am 'add logical_disjunction'
Logical Disjunction also known as “OR” returns
first_input or second_inputFalse, if the first input is False and the second input is False
is the Logical Negation (NOT) of Logical NOR which returns True only if
first_inputis False andsecond_inputis False
examples of Logical Disjunction
the system works, if the inputs are
is the main system running?
is the backup system running?
is main running?
is backup running?
is system working?
yes
yes
yes
yes
no
yes
no
yes
yes
no
no
no
emergency room triage, if the inputs are
is it life threatening?
is patient a child?
life threat?
child?
treat immediately
yes
yes
yes
yes
no
yes
no
yes
yes
no
no
no
automatic door that opens, if the inputs are
has keycard?
entered code?
has keycard?
entered code?
open door
yes
yes
yes
yes
no
yes
no
yes
yes
no
no
no
give discount if the person is already a customer or has a coupon, if the inputs are
is already a customer?
has coupon code?
already customer
has coupon
give discount
yes
yes
yes
yes
no
yes
no
yes
yes
no
no
no
elevator moves, if the inputs are
did I push the button?
did someone else push the button?
I pushed
someone else pushed
elevator moves
yes
yes
yes
yes
no
yes
no
yes
yes
no
no
no
close the project
I close
test_binary.pyandtruth_table.pyI click in the terminal where the tests are running
I use q on the keyboard to leave the tests. The terminal goes back to the command line.
I change directory to the parent of
truth_tablecd ..the terminal shows
.../pumping_pythonI am back in the
pumping_pythondirectory
review
Binary Operations take two inputs, each input can be True or False. If I name the first input first_input and the second input second_input, the tests show that
-
returns
first_input or second_inputreturns False only if
first_inputis False andsecond_inputis Falseis the Logical Negation (NOT) of Logical NOR which returns True only if
first_inputis False andsecond_inputis False
first input
second input
return
True
True
True
True
False
True
False
True
True
False
False
False
-
always returns True
never returns False
is the Logical Negation (NOT) of contradiction which always returns False
first input
second input
return
True
True
True
True
False
True
False
True
True
False
False
True
-
returns
not (first_input and second_input)returns False only if
first_inputis True andsecond_inputis Trueis the Logical Negation (NOT) of Logical Conjunction (AND) which returns True only if
first_inputis True andsecond_inputis True
first input
second input
return
True
True
False
True
False
True
False
True
True
False
False
True
-
always returns
not first_inputreturns True only if
first_inputis Falseis the Logical Negation (NOT) of Project First which returns True only if
first_inputis True
first input
second input
return
True
True
False
True
False
False
False
True
True
False
False
True
-
returns
not first_input and second_inputreturns True only if
first_inputis False andsecond_inputis Trueis the Logical Negation (NOT) of Converse Implication which returns False if
first_inputis False andsecond_inputis True
first input
second input
return
True
True
False
True
False
False
False
True
True
False
False
False
-
always returns
second_inputreturns True only if
second_inputis Trueis the Logical Negation (NOT) of Negate Second which returns True only if
second_inputis False
first input
second input
return
True
True
True
True
False
False
False
True
True
False
False
False
Logical Conjunction returns
returns
first_input and second_inputreturns True only if
first_inputis True andsecond_inputis Trueis the Logical Negation (NOT) of Logical NAND which returns False only if
first_inputis True andsecond_inputis True
first input
second input
return
True
True
True
True
False
False
False
True
False
False
False
False
-
always returns False
never returns True
is the Logical Negation (NOT) of Tautology which always returns True
first input
second input
return
True
True
False
True
False
False
False
True
False
False
False
False
and
Three binary operations were written with AND, three with NOT and one was written with OR.
return |
True, True |
True, False |
False, True |
False, False |
name of operation |
|---|---|---|---|---|---|
False |
False |
False |
False |
False |
|
first and second |
True |
False |
False |
False |
|
second |
True |
False |
True |
False |
|
(not first) and second |
False |
False |
True |
False |
|
not first |
False |
False |
True |
True |
|
not (first and second) |
False |
True |
True |
True |
|
True |
True |
True |
True |
True |
|
first or second |
True |
True |
True |
False |
code from the chapter
Do you want to see all the CODE I typed for the Truth Table?
what is next?
rate pumping python
If this has been a 7 star experience for you, please CLICK HERE to leave a 5 star review of pumping python. It helps other people get into the book too.