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(logical_conjunction(True, True))
19 self.assertFalse(logical_conjunction(True, False))
20 self.assertFalse(logical_conjunction(False, True))
21 self.assertFalse(logical_conjunction(False, False))
23 def test_project_second(self):
24 project_second = src.truth_table.project_second
25 self.assertTrue(project_second(True, True))
26 self.assertFalse(project_second(True, False))
27 self.assertTrue(project_second(False, True))
28 self.assertFalse(project_second(False, False))
29
30 def test_converse_non_implication(self):
31 converse_non_implication = (
32 src.truth_table.converse_non_implication
33 )
34 self.assertFalse(converse_non_implication(True, True))
35 self.assertFalse(converse_non_implication(True, False))
36 self.assertTrue(converse_non_implication(False, True))
37 self.assertFalse(converse_non_implication(False, False))
39 def test_negate_first(self):
40 negate_first = src.truth_table.negate_first
41 self.assertFalse(negate_first(True, True))
42 self.assertFalse(negate_first(True, False))
43 self.assertTrue(negate_first(False, True))
44 self.assertTrue(negate_first(False, False))
45
46 def test_logical_nand(self):
47 nand = src.truth_table.logical_nand
48 self.assertFalse(nand(True, True))
49 self.assertTrue(nand(True, False))
50 self.assertTrue(nand(False, True))
51 self.assertTrue(nand(False, False))
53 def test_tautology(self):
54 tautology = src.truth_table.tautology
55 self.assertTrue(tautology(True, True))
56 self.assertTrue(tautology(True, False))
57 self.assertTrue(tautology(False, True))
58 self.assertTrue(tautology(False, False))
59
60 def test_logical_disjunction(self):
61 logical_disjunction = (
62 src.truth_table.logical_disjunction
63 )
64 self.assertTrue(logical_disjunction(True, True))
65 self.assertTrue(logical_disjunction(True, False))
66 self.assertTrue(logical_disjunction(False, True))
67 self.assertFalse(logical_disjunction(False, False))
68
69
70# Exceptions seen
71# AttributeError
72# TypeError
73# AssertionError
74# SyntaxError
open 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_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 if the first input is True and the second input is True, to test_binary.py
first input |
second input |
return |
|---|---|---|
True |
True |
False |
37 self.assertFalse(converse_non_implication(False, False))
38
39 def test_negate_first(self):
40 negate_first = src.truth_table.negate_first
41 self.assertFalse(negate_first(True, True))
42
43
44# 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/__init__.pyfrom thesrcfolderI add
negate_firsttotruth_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.
negate_first(True , True ) -> False
REFACTOR: make it better
I add an assertion for the second case, which is if 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
39 def test_negate_first(self): 40 negate_first = src.truth_table.negate_first 41 self.assertFalse(negate_first(True, True)) 42 self.assertFalse(negate_first(True, False)) 43 44 45# 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.
negate_first(True , False) -> False negate_first(True , True ) -> FalseI add an assertion for the next case, which is if the first input is False and the second input is True
first input
second input
return
False
True
True
39 def test_negate_first(self): 40 negate_first = src.truth_table.negate_first 41 self.assertFalse(negate_first(True, True)) 42 self.assertFalse(negate_first(True, False)) 43 self.assertTrue(negate_first(False, True)) 44 45 46# 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
negate_first(False, True ) -> True negate_first(True , False) -> False negate_first(True , True ) -> FalseI add an assertion for the last case, which is if 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
39 def test_negate_first(self): 40 negate_first = src.truth_table.negate_first 41 self.assertFalse(negate_first(True, True)) 42 self.assertFalse(negate_first(True, False)) 43 self.assertTrue(negate_first(False, True)) 44 self.assertTrue(negate_first(False, False)) 45 46 47# Exceptions seenthe test is still green because Python checks if
first_inputis equal to False whenif first_input == False:runs,if
first_inputis NOT equal to False, it leaves the if statement and continues to run the rest of the function -return Falsethen leaves the function since the return statement is the last thing to run in a functionnegate_first(True , True ) -> False └── def negate_first(first_input, second_input): ├── first_input == True ├── second_input == True ├── if first_input == False: │ return True └── return Falsenegate_first(True , False) -> False └── def negate_first(first_input, second_input): ├── first_input == True ├── second_input == False ├── if first_input == False: │ return True └── return Falseif
first_inputis equal to False, it goes to the next line -return Truethen leaves the function since the return statement is the last thing to run in a functionnegate_first(False, True ) -> True └── def negate_first(first_input, second_input): ├── first_input == False ├── second_input == True └── if first_input == False: └── return True else: return Falsenegate_first(False, False) -> True └── def negate_first(first_input, second_input): ├── first_input == False ├── second_input == False └── if first_input == False: └── return True else: return False
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 not bool(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 not bool(first_input) == True: 41 if not bool(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 not bool(first_input) == True: 41 # if not bool(first_input): 42 if not first_input: 43 return True 44 return Falsethe test is still green because Python checks the value of
not first_inputwhenif not first_input:runsif the value of
somethingis Falsesomething = False if something == False if bool(something) == False if bool(False ) == False # use the value if False == False # bool(False) returns False if True == True # write in terms of True if True # remove '== True' if not False # not False == True if not something # use the name for the valueif the value of
somethingis Truesomething = True if something == False if bool(something) == False if bool(True ) == False # use the value if True == False # bool(True) returns True if False == True # write in terms of True if not True == True # write in terms of True if not True # remove '== True' if not something # use the name for the value
if bool(something) == Falseis the same asif not bool(something) == Trueis the same asif not bool(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 not bool(first_input) == True: 41 # if not bool(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 not bool(first_input) == True: 41 # if not bool(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.
if not first_input: vs return True return True vs if not first_input else: vs else return False vs FalseI remove
True ifandelse False37def negate_first(first_input, second_input): 38 # if first_input == False: 39 # if bool(first_input) == False: 40 # if not bool(first_input) == True: 41 # if not bool(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 the other 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, it negates the first input.
examples of Negate First
approval to do something based only on risk, if the inputs are
is it risky?
has a good reason?
is risky?
good reason?
approved
yes
yes
no
yes
no
no
no
yes
yes
no
no
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 if the first input is True and the second input is True, to
test_binary.pyfirst input
second input
return
True
True
False
44 self.assertTrue(negate_first(False, False)) 45 46 def test_logical_nand(self): 47 nand = src.truth_table.logical_nand 48 self.assertFalse(nand(True, True)) 49 50 51# 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 logical_nand 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.
logical_nand(True , True ) -> False
REFACTOR: make it better
I add an assertion for the second case, which is if 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
46 def test_logical_nand(self): 47 nand = src.truth_table.logical_nand 48 self.assertFalse(nand(True, True)) 49 self.assertTrue(nand(True, False)) 50 51 52# 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
logical_nand(True , False) -> True logical_nand(True , True ) -> FalseI 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
46 def test_logical_nand(self): 47 nand = src.truth_table.logical_nand 48 self.assertFalse(nand(True, True)) 49 self.assertTrue(nand(True, False)) 50 self.assertTrue(nand(False, True)) 51 52 53# Exceptions seenthe terminal is my friend, and shows AssertionError
AssertionError: False is not truebecause Python checks if
second_inputis equal to False whenif second_input == False:runs,if
second_inputis NOT equal to False, it leaves the if statement and continues to run the rest of the function -return Falsethen 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 Truethen 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
logical_nand(False, True ) -> True logical_nand(True , False) -> True logical_nand(True , True ) -> FalseI add an assertion for the last case, which is if 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
46 def test_logical_nand(self): 47 nand = src.truth_table.logical_nand 48 self.assertFalse(nand(True, True)) 49 self.assertTrue(nand(True, False)) 50 self.assertTrue(nand(False, True)) 51 self.assertTrue(nand(False, False)) 52 53 54# Exceptions seenthe test is still green because 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 Truethen leaves the function since the return statement is the last thing to run in a functionlogical_nand(False, False) -> True └── def logical_nand(first_input, second_input): ├── first_input == False ├── second_input == False └── if first_input == False: └── return True if second_input == False: return True return Falselogical_nand(False, True ) -> True └── def logical_nand(first_input, second_input): ├── first_input == False ├── second_input == True └── if first_input == False: └── return True if second_input == False: return True return Falseif
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 equal to False, it goes to the next line -return Truethen leaves the function since the return statement is the last thing to run in a functionlogical_nand(True , False) -> True └── def logical_nand(first_input, second_input): ├── first_input == True ├── second_input == False ├── if first_input == False: │ return True └── if second_input == False: └── return True return Falseif
second_inputis NOT equal to False, it leaves the if statement and continues to run the rest of the function -return Falsethen leaves the function since the return statement is the last thing to run in a functionlogical_nand(True , True ) -> False └── def logical_nand(first_input, second_input): ├── first_input == True ├── second_input == True ├── if first_input == False: │ return True ├── if second_input == False: │ return True └── return False
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
logical_nand(False, False) -> True logical_nand(False, True ) -> True logical_nand(True , False) -> True logical_nand(True , True ) -> FalsePython checks if
first_inputis equal to True whenif first_input == True:runsif
first_inputis NOT equal to True, it leaves the if statement and continues to run the rest of the function -return Truethen leaves the function since the return statement is the last thing to run in a functionlogical_nand(False, False) -> True └── def logical_nand(first_input, second_input): ├── first_input == False ├── second_input == False ├── if first_input == True: │ if second_input == True: │ return False └── return Truelogical_nand(False, True ) -> True └── def logical_nand(first_input, second_input): ├── first_input == False ├── second_input == True ├── if first_input == True: │ if second_input == True: │ return False └── return Trueif
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 Truethen leaves the function since the return statement is the last thing to run in a functionlogical_nand(True , False) -> True └── def logical_nand(first_input, second_input): ├── first_input == True ├── second_input == False └── if first_input == True: ┌───┴── if second_input == True: │ return False └── return Trueif
second_inputis equal to True, it goes to the next line -return Falsethen leaves the function since the return statement is the last thing to run in a functionlogical_nand(True , True ) -> False └── def logical_nand(first_input, second_input): ├── first_input == True ├── second_input == True └── if first_input == True: └── if second_input == True: └── return False return True
it only checks the second input if the first input is True.
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 Falsesomething = False if something == True if bool(something) == True if bool(False ) == True # use the value if False == True # bool(False) returns False if not True == True # write in terms of True if not True # remove '== True' if False # not True == False if something # use the name for the valueif the value of
somethingis Truesomething = True if something == True if bool(something) == True if bool(True ) == True # use the value if True == True # bool(True) returns True if True # remove '== True' if something # use the name for the value
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)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 if not (first_input and second_input): 59 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 clause41def 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 else: 60 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.
if not ( vs return True first_input and second_input ): return True vs if not (first_input and second_input) else: vs else return False vs FalseI 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 True.logical_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 logical_conjunction(True, True) not (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 logical_conjunction(True, False) not (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 logical_conjunction(False, True) not (False ) Trueif the first input is False and the second input is False, logical_nand returns
not (first and second) not (False and False ) # not logical_conjunction(False, False) not (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(first_input, second_input) 63 ) 64 return ( 65 # True if 66 not (first_input and second_input) 67 # else False 68 )the test is still green.
logical_nand(False, False) -> True └── not logical_conjunction(False , False) -> True logical_nand(False, True ) -> True └── not logical_conjunction(False , True ) -> True logical_nand(True , False) -> True └── not logical_conjunction(True , False) -> True logical_nand(True , True ) -> False └── not logical_conjunction(True , True ) -> FalseI remove the comments
41def logical_nand(first_input, second_input): 42 return logical_negation( 43 logical_conjunction(first_input, second_input) 44 ) 45 return not (first_input and second_input)I can use any of these two return statements, only the first one will run 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 words.is 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 the negation of 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 if the first input is True and the second input is True, to
test_binary.pyfirst input
second input
return
True
True
True
51 self.assertTrue(nand(False, False)) 52 53 def test_tautology(self): 54 tautology = src.truth_table.tautology 55 self.assertTrue(tautology(True, True)) 56 57 58# 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 tautology to truth_table.py
41def logical_nand(first_input, second_input):
42 return logical_negation(
43 logical_conjunction(first_input, second_input)
44 )
45 return not (first_input and second_input)
46
47
48def tautology(first_input, second_input):
49 return True
the test passes. tautology returns True, if the first input is True and the second input is True.
tautology(True , True ) -> True
REFACTOR: make it better
I add an assertion for the next case, which is if 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
53 def test_tautology(self): 54 tautology = src.truth_table.tautology 55 self.assertTrue(tautology(True, True)) 56 self.assertTrue(tautology(True, False)) 57 58 59# 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
tautology(True , False) -> True tautology(True , True ) -> TrueI add an assertion for the next case, which is if the first input is False and the second input is True
first input
second input
return
False
True
True
53 def test_tautology(self): 54 tautology = src.truth_table.tautology 55 self.assertTrue(tautology(True, True)) 56 self.assertTrue(tautology(True, False)) 57 self.assertTrue(tautology(False, True)) 58 59 60# 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
tautology(False, True ) -> True tautology(True , False) -> True tautology(True , True ) -> TrueI add an assertion for the last case, which is if the first input is False and the second input is False
first input
second input
return
False
False
True
53 def test_tautology(self): 54 tautology = src.truth_table.tautology 55 self.assertTrue(tautology(True, True)) 56 self.assertTrue(tautology(True, False)) 57 self.assertTrue(tautology(False, True)) 58 self.assertTrue(tautology(False, False)) 59 60 61# Exceptions seenstill green, there is only one result for this operation.
tautology(False, False) -> True tautology(False, True ) -> True tautology(True , False) -> True tautology(True , True ) -> TrueI 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 if the first input is True and the second input is True, to
test_binary.pyfirst input
second input
return
True
True
True
58 self.assertTrue(tautology(False, False)) 59 60 def test_logical_disjunction(self): 61 logical_disjunction = ( 62 src.truth_table.logical_disjunction 63 ) 64 self.assertTrue(logical_disjunction(True, True)) 65 66 67# 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 logical_disjunction to truth_table.py
48def tautology(first_input, second_input):
49 return True
50
51
52def logical_disjunction(first_input, second_input):
53 return True
the test passes. logical_disjunction returns True, if the first input is True and the second input is True.
logical_disjunction(True , True ) -> True
REFACTOR: make it better
I add an assertion for the next case, which is if 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
60 def test_logical_disjunction(self): 61 logical_disjunction = ( 62 src.truth_table.logical_disjunction 63 ) 64 self.assertTrue(logical_disjunction(True, True)) 65 self.assertTrue(logical_disjunction(True, False)) 66 67 68# 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.
logical_disjunction(True , False) -> True tautology(True , False) -> True logical_disjunction(True , True ) -> True tautology(True , True ) -> TrueI add an assertion for the next case, which is if the first input is False and the second input is True
first input
second input
return
False
True
True
60 def test_logical_disjunction(self): 61 logical_disjunction = ( 62 src.truth_table.logical_disjunction 63 ) 64 self.assertTrue(logical_disjunction(True, True)) 65 self.assertTrue(logical_disjunction(True, False)) 66 self.assertTrue(logical_disjunction(False, True)) 67 68 69# 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
logical_disjunction(False, True ) -> True tautology(False, True ) -> True logical_disjunction(True , False) -> True tautology(True , False) -> True logical_disjunction(True , True ) -> True tautology(True , True ) -> TrueI add an assertion for the fourth case, which is if the first input is False and the second input is False
first input
second input
return
False
False
False
60 def test_logical_disjunction(self): 61 logical_disjunction = ( 62 src.truth_table.logical_disjunction 63 ) 64 self.assertTrue(logical_disjunction(True, True)) 65 self.assertTrue(logical_disjunction(True, False)) 66 self.assertTrue(logical_disjunction(False, True)) 67 self.assertFalse(logical_disjunction(False, False)) 68 69 70# 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.py52def logical_disjunction(first_input, second_input): 53 if first_input == False: 54 if second_input == False: 55 return False 56 return Truethe test passes because Python checks if
first_inputis equal to False whenif first_input == False:runsif
first_inputis NOT equal to False, it leaves the if statement and continues to run the rest of the function -return Truethen leaves the function since the return statement is the last thing to run in a functionlogical_disjunction(True , True ) -> True └── def logical_disjunction(first_input, second_input): ├── first_input == True ├── second_input == True ├── if first_input == False: │ if second_input == False: │ return False └── return Truelogical_disjunction(True , False) -> True └── def logical_disjunction(first_input, second_input): ├── first_input == True ├── second_input == False ├── if first_input == False: │ if second_input == False: │ return False └── return Trueif
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 Truethen leaves the function since the return statement is the last thing to run in a functionlogical_disjunction(False, True ) -> True └── def logical_disjunction(first_input, second_input): ├── first_input == False ├── second_input == True └── if first_input == False: ┌───┴── if second_input == False: │ return False └── return Trueif
second_inputis equal to False, it goes to the next line -return Falsethen leaves the function since the return statement is the last thing to run in a functionlogical_disjunction(False, False) -> False └── def logical_disjunction(first_input, second_input): ├── first_input == False ├── second_input == False └── if first_input == False: └── if second_input == False: └── return False return True
it only checks the second input if the first input is False.
I add the bool built-in function
52def logical_disjunction(first_input, second_input): 53 # if first_input == False: 54 if bool(first_input) == False: 55 # if second_input == False: 56 if bool(second_input) == False: 57 return False 58 return Truethe test is still green.
I use Logical Negation (NOT) to write the if statements in terms of True
52def logical_disjunction(first_input, second_input): 53 # if first_input == False: 54 # if bool(first_input) == False: 55 if not bool(first_input) == True: 56 # if second_input == False: 57 # if bool(second_input) == False: 58 if not bool(second_input) == True: 59 return False 60 return Truestill green.
I remove
== True52def logical_disjunction(first_input, second_input): 53 # if first_input == False: 54 # if bool(first_input) == False: 55 # if not bool(first_input) == True: 56 if not bool(first_input): 57 # if second_input == False: 58 # if bool(second_input) == False: 59 # if not bool(second_input) == True: 60 if not bool(second_input): 61 return False 62 return Truegreen.
I remove bool
52def logical_disjunction(first_input, second_input): 53 # if first_input == False: 54 # if bool(first_input) == False: 55 # if not bool(first_input) == True: 56 # if not bool(first_input): 57 if not first_input: 58 # if second_input == False: 59 # if bool(second_input) == False: 60 # if not bool(second_input) == True: 61 # if not bool(second_input): 62 if not second_input: 63 return False 64 return Truestill green because I can assume the following substitutions for
if something == False:if the value of
somethingis Falsesomething = False if something == False if bool(something) == False if bool(False ) == False # use the value if False == False # bool(False) returns False if True == True # write in terms of True if True # remove '== True' if not False # not False == True if not something # use the name for the valueif the value of
somethingis Truesomething = True if something == False if bool(something) == False if bool(True ) == False # use the value if True == False # bool(True) returns True if False == True # write in terms of True if not True == True # write in terms of True if not True # remove '== True' if not something # use the name for the value
if bool(something) == Falseis the same asif not bool(something) == Trueis the same asif not bool(something)is the same asif not something.I use Logical Conjunction (AND) to put the two if statements together
52def logical_disjunction(first_input, second_input): 53 # if first_input == False: 54 # if bool(first_input) == False: 55 # if not bool(first_input) == True: 56 # if not bool(first_input): 57 # if not first_input: 58 # if second_input == False: 59 # if bool(second_input) == False: 60 # if not bool(second_input) == True: 61 # if not bool(second_input): 62 # if not second_input: 63 if not first_input and not second_input: 64 return False 65 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
52def logical_disjunction(first_input, second_input): 53 # if first_input == False: 54 # if bool(first_input) == False: 55 # if not bool(first_input) == True: 56 # if not bool(first_input): 57 # if not first_input: 58 # if second_input == False: 59 # if bool(second_input) == False: 60 # if not bool(second_input) == True: 61 # if not bool(second_input): 62 # if not second_input: 63 if not first_input and not second_input: 64 return False 65 else: 66 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
52def logical_disjunction(first_input, second_input): 53 # if first_input == False: 54 # if bool(first_input) == False: 55 # if not bool(first_input) == True: 56 # if not bool(first_input): 57 # if not first_input: 58 # if second_input == False: 59 # if bool(second_input) == False: 60 # if not bool(second_input) == True: 61 # if not bool(second_input): 62 # if not second_input: 63 # else: 64 if not (not first_input and not second_input): 65 return True 66 if not first_input and not second_input: 67 return Falsethe test is still green.
I change it to an else clause
52def logical_disjunction(first_input, second_input): 53 # if first_input == False: 54 # if bool(first_input) == False: 55 # if not bool(first_input) == True: 56 # if not bool(first_input): 57 # if not first_input: 58 # if second_input == False: 59 # if bool(second_input) == False: 60 # if not bool(second_input) == True: 61 # if not bool(second_input): 62 # if not second_input: 63 # else: 64 if not (not first_input and not second_input): 65 return True 66 # if not first_input and not second_input: 67 else: 68 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.
if not ( vs return True not first_input and not second_input ): return True vs if not ( not first_input and not second_input ) else: vs else return False vs FalseI 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.py67 self.assertFalse(logical_disjunction(False, False)) 68 69 70# Exceptions seen 71# AttributeError 72# TypeError 73# AssertionError 74# SyntaxErrorI change
not andtoorin the logical_disjunction function intruth_table.py60 return ( 61 (not not first_input) 62 # (not and) 63 or 64 (not not second_input) 65 )the test is green again
I remove
not notbecause they cancel out60 return ( 61 # (not not first_input) 62 first_input 63 # (not and) 64 or 65 # (not not second_input) 66 second_input 67 )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
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
52def logical_disjunction(first_input, second_input): 53 # if first_input == False: 54 # if bool(first_input) == False: 55 # if not bool(first_input) == True: 56 # if not bool(first_input): 57 # if not first_input: 58 # if second_input == False: 59 # if bool(second_input) == False: 60 # if not bool(second_input) == True: 61 # if not bool(second_input): 62 # if not second_input: 63 # else: 64 # if not (not first_input and not second_input): 65 # return True 66 # if not first_input and not second_input: 67 # else: 68 # return False 69 # return ( 70 # True if 71 # not (not first_input and not second_input) 72 # else False 73 # ) 74 return logical_negation( 75 logical_conjunction( 76 logical_negation(first_input), 77 logical_negation(second_input) 78 ) 79 ) 80 return ( 81 # (not not first_input) 82 first_input 83 # (not and) 84 or 85 # (not not second_input) 86 second_input 87 )still green.
logical_disjunction(False, False) -> False └── not logical_conjunction(True, True) not True -> False logical_disjunction(False, True ) -> True └── not logical_conjunction(True , False) not False -> True logical_disjunction(True , False) -> True └── not logical_conjunction(False, True ) not False -> True logical_disjunction(True , True ) -> True └── not logical_conjunction(False, False) not False -> TrueI remove the commented lines
52def logical_disjunction(first_input, second_input): 53 return logical_negation( 54 logical_conjunction( 55 logical_negation(first_input), 56 logical_negation(second_input) 57 ) 58 ) 59 return first_input or second_inputI can use any of these two return statements, only the first one will run 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_input.False, 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.