truth table: Binary Operations 1
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))
38
39
40# Exceptions seen
41# AttributeError
42# TypeError
43# AssertionError
questions about Binary Operations 1
Questions to think about as I go through the chapter
requirements
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 use touch to make a new Python file named
test_binary.pyin thetestsdirectorytouch tests/test_binary.pyNew-Item tests/test_binary.pyI add
test_binary.pyto git for trackinggit add tests/test_binary.pyI open
test_binary.pyfrom thetestsfolderI 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 4 items tests/test_nullary_unary.py .... [100%] ================== 4 passed in G.HIs ===================
test_contradiction
The truth table for contradiction is
first input |
second input |
return |
|---|---|---|
True |
True |
False |
True |
False |
False |
False |
True |
False |
False |
False |
False |
RED: make it fail
I add a test for contradiction with an assertion for if the first input is True and the second input is True, in
test_binary.pyfirst input
second input
return
True
True
False
1import src.truth_table 2import unittest 3 4 5class TestBinaryOperations(unittest.TestCase): 6 7 def test_contradiction(self): 8 self.assertFalse( 9 src.truth_table.contradiction(True, True) 10 ) 11 12 13# Exceptions seenthe terminal is my friend, and shows AttributeError
AttributeError: module 'src.truth_table' has no attribute 'contradiction'because I have not defined contradiction in
truth_table.pyI add AttributeError to the list of Exceptions seen
13# Exceptions seen 14# AttributeError
GREEN: make it pass
I open
truth_table/__init__.pyfrom thesrcfolderI add
contradictiontotruth_table.py13def logical_negation(the_input): 14 return not the_input 15 16 17def contradiction(): 18 return Nonethe terminal is my friend, and shows TypeError
TypeError: contradiction() takes 0 positional arguments but 2 were givenbecause the test called the contradiction function with two arguments (True and True) and the definition does not allow any arguments (the parentheses are empty).
I add TypeError to the list of Exceptions , in
test_binary.py13# Exceptions seen 14# AttributeError 15# TypeErrorI add
first_inputas the name of the first argument in the function signature for contradiction, intruth_table.py17# def contradiction(): 18def contradiction(first_input): 19 return Nonethe terminal is my friend, and shows TypeError
TypeError: contradiction() takes 1 positional argument but 2 were givenbecause the test called the contradiction function with two arguments (True and True) and I just changed the definition to only allow calls with one argument.
I add
second_inputas the name of the second input in parentheses17# def contradiction(): 18# def contradiction(first_input): 19def contradiction(first_input, second_input): 20 return Nonethe test passes because None is grouped as False (the result of bool(None) is False) and the assertion expects False.
contradiction(True, True) -> NoneUsing substitution since I can treat a call to a function as the object it returns
assertFalse(src.truth_table.contradiction(True, True)) assertFalse(None ) assertFalse(bool(None) ) assertFalse(False )
REFACTOR: make it better
I change the return statement to make it clearer
17# def contradiction(): 18# def contradiction(first_input): 19def contradiction(first_input, second_input): 20 # return None 21 return Falsethe test is still green. contradiction returns False, if the first input is True and the second input is True.
I remove the commented lines from
contradiction13def logical_negation(the_input): 14 return not the_input 15 16 17def contradiction(first_input, second_input): 18 return FalseI add an assertion for the second case, which is if the first input is True and the second input is False, to
test_binary.pyfirst input
second input
return
True
False
False
7 def test_contradiction(self): 8 self.assertFalse( 9 src.truth_table.contradiction(True, True) 10 ) 11 self.assertFalse( 12 src.truth_table.contradiction(True, False) 13 ) 14 15 16# Exceptions seenthe test is still green. contradiction returns False
if the first input is True and the second input is False
if the first input is True and the second input is True
if the first input is True
contradiction(True, False) -> False contradiction(True, True ) -> FalseI add an assertion for the third case, which is if the first input is False and the second input is True
first input
second input
return
False
True
False
7 def test_contradiction(self): 8 self.assertFalse( 9 src.truth_table.contradiction(True, True) 10 ) 11 self.assertFalse( 12 src.truth_table.contradiction(True, False) 13 ) 14 self.assertFalse( 15 src.truth_table.contradiction(False, True) 16 ) 17 18 19# Exceptions seenthe test is still green. contradiction returns False
if the first input is False and the second input is True
if the first input is True
contradiction(False, True ) -> False contradiction(True , False) -> False contradiction(True , True ) -> FalseI 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
7 def test_contradiction(self): 8 self.assertFalse( 9 src.truth_table.contradiction(True, True) 10 ) 11 self.assertFalse( 12 src.truth_table.contradiction(True, False) 13 ) 14 self.assertFalse( 15 src.truth_table.contradiction(False, True) 16 ) 17 self.assertFalse( 18 src.truth_table.contradiction(False, False) 19 ) 20 21 22# Exceptions seenthe test is still green. contradiction returns False
if the first input is False
if the first input is True
contradiction(False, False) -> False contradiction(False, True ) -> False contradiction(True , False) -> False contradiction(True , True ) -> FalseI add a variable for
src.truth_table.contradiction7 def test_contradiction(self): 8 contradiction = src.truth_table.contradiction 9 self.assertFalse( 10 src.truth_table.contradiction(True, True) 11 ) 12 self.assertFalse( 13 src.truth_table.contradiction(True, False) 14 ) 15 self.assertFalse( 16 src.truth_table.contradiction(False, True) 17 ) 18 self.assertFalse( 19 src.truth_table.contradiction(False, False) 20 ) 21 22 23# Exceptions seenI use the variable to remove repetition of
src.truth_table.contradiction7 def test_contradiction(self): 8 contradiction = src.truth_table.contradiction 9 self.assertFalse( 10 # src.truth_table.contradiction(True, True) 11 contradiction(True, True) 12 ) 13 self.assertFalse( 14 # src.truth_table.contradiction(True, False) 15 contradiction(True, False) 16 ) 17 self.assertFalse( 18 # src.truth_table.contradiction(False, True) 19 contradiction(False, True) 20 ) 21 self.assertFalse( 22 # src.truth_table.contradiction(False, False) 23 contradiction(False, False) 24 ) 25 26 27# Exceptions seenthe test is still green.
I remove the commented lines from test_contradiction
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 15# Exceptions seenI add a git commit message in the other terminal
git commit -am 'add contradiction'
contradiction always returns False, it does not care about the inputs
examples of Contradiction
A broken light switch, if the inputs are
is the switch on?
is there electricity?
If the switch is broken, the inputs do not matter
switch
electricity
bulb
on
on
off
on
off
off
off
on
off
off
off
off
A rule that does not allow watching TV, if the inputs are
is homework done?
is the room clean?
the rule does not take the inputs into consideration
homework done
clean room
can watch TV
yes
yes
no
yes
no
no
no
yes
no
no
no
no
A rule about loaning money to friends, if the inputs are
person can be trusted?
is a small amount?
trusted person
small amount
loan money to friend
yes
yes
no
yes
no
no
no
yes
no
no
no
no
Do not disturb, if the inputs are
is the person in favorites list?
is it during allowed hours?
favorites
allowed hours
allow to ring
yes
yes
no
yes
no
no
no
yes
no
no
no
no
Broken Multi Factor Authentication to log in, if the inputs are
did the user provide the right password?
did the user provide the right MFA code?
right password
right MFA code
log in
yes
yes
no
yes
no
no
no
yes
no
no
no
no
test_logical_conjunction
The truth table for logical_conjunction is
first input |
second input |
return |
|---|---|---|
True |
True |
True |
True |
False |
False |
False |
True |
False |
False |
False |
False |
RED: make it fail
I go back to the terminal where the tests are running
I add a test for logical_conjunction with an assertion for the first case, which is if the first input is True and the second input is True, in
test_binary.pyfirst input
second input
return
True
True
True
12 self.assertFalse(contradiction(False, False)) 13 14 def test_logical_conjunction(self): 15 self.assertTrue( 16 src.truth_table.logical_conjunction(True, True) 17 ) 18 19 20# Exceptions seenthe terminal is my friend, and shows AttributeError
AttributeError: module 'src.truth_table' has no attribute 'logical_conjunction'. Did you mean: 'logical_negation'?because there is nothing named logical_conjunction in
truth_table.py, yet.
GREEN: make it pass
I add logical_conjunction to truth_table.py
17def contradiction(first_input, second_input):
18 return False
19
20
21def logical_conjunction(first_input, second_input):
22 return True
the test passes. logical_conjunction returns True, if the first input is True and the second input is True.
logical_conjunction(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_conjunction in
test_binary.pyfirst input
second input
return
True
False
False
14 def test_logical_conjunction(self): 15 self.assertTrue( 16 src.truth_table.logical_conjunction( 17 True, True 18 ) 19 ) 20 self.assertFalse( 21 src.truth_table.logical_conjunction( 22 True, False 23 ) 24 ) 25 26 27# Exceptions seenthe terminal is my friend, and shows AssertionError
AssertionError: True is not falsebecause the function returns True and the assertion expects False. Using substitution since I can treat a call to a function as the object it returns
assertFalse(src.truth_table.logical_conjunction(True, False)) assertFalse(True )I add AssertionError to the list of Exceptions seen, in
test_binary.py27# Exceptions seen 28# AttributeError 29# TypeError 30# AssertionErrorI make the logical_conjunction function in
truth_table.pyreturn False21def logical_conjunction(first_input, second_input): 22 # return True 23 return Falsethe terminal is my friend, and shows AssertionError
AssertionError: False is not truebecause the function now returns False and the assertion before this one, expects True.
logical_conjunction has to make a choice. It should return
False, 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
the second input in these 2 cases
I change the return statement of the logical_conjunction function in
truth_table.py21def logical_conjunction(first_input, second_input): 22 # return False 23 # return True 24 return second_inputthe test passes.
logical_conjunction(True, False) -> False logical_conjunction(True, True ) -> TrueI add an assertion for the third case, which is if the first input is False and the second input is True, to test_logical_conjunction in
test_binary.pyfirst input
second input
return
False
True
False
14 def test_logical_conjunction(self): 15 self.assertTrue( 16 src.truth_table.logical_conjunction( 17 True, True 18 ) 19 ) 20 self.assertFalse( 21 src.truth_table.logical_conjunction( 22 True, False 23 ) 24 ) 25 self.assertFalse( 26 src.truth_table.logical_conjunction( 27 False, True 28 ) 29 ) 30 31 32# Exceptions seenthe terminal is my friend, and shows AssertionError
AssertionError: True is not falsebecause my solution does not work for this case. The function returns True and the assertion expects False. The logical_conjunction function has to make a choice, it should return
False, if the first input is False and the second input is True
False, 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
I can use if statements to make it choose what to do based on the inputs.
if statements
An if statement is a way for a program to choose what to do based on something else. I can use if statements to make a function choose between two things. They are written this way in Python
if something:
then do this
I add an if statement for when the first input is False to the logical_conjunction function in
truth_table.py21def logical_conjunction(first_input, second_input): 22 # return False 23 # return True 24 if first_input == False: 25 return False 26 return second_inputthe test passes. logical_conjunction returns
False, if the first input is False
the second input if the above condition is NOT met
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 second_input, which returns the value ofsecond_inputas the output, then leaves the function since the return statement is the last thing to run in a functionlogical_conjunction(True , True ) -> True └── def logical_conjunction(first_input, second_input): ├── first_input == True ├── second_input == True ├── if first_input == False: │ return False └── return second_inputlogical_conjunction(True , False) -> False └── def logical_conjunction(first_input, second_input): ├── first_input == True ├── second_input == False ├── if first_input == False: │ return False └── return second_inputif
first_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_conjunction(False, True ) -> False └── def logical_conjunction(first_input, second_input): ├── first_input == False ├── second_input == False └── if first_input == False: └── return False return second_input
I add an assertion for the last case, which is if the first input is False and the second input is False, to test_logical_conjunction in
test_binary.pyfirst input
second input
return
False
False
False
14 def test_logical_conjunction(self): 15 self.assertTrue( 16 src.truth_table.logical_conjunction( 17 True, True 18 ) 19 ) 20 self.assertFalse( 21 src.truth_table.logical_conjunction( 22 True, False 23 ) 24 ) 25 self.assertFalse( 26 src.truth_table.logical_conjunction( 27 False, True 28 ) 29 ) 30 self.assertFalse( 31 src.truth_table.logical_conjunction( 32 False, False 33 ) 34 ) 35 36 37# Exceptions seenthe test is still green.
There is only one case where logical_conjunction returns True, I add an if statement for it in
truth_table.py21def logical_conjunction(first_input, second_input): 22 # return False 23 # return True 24 # if first_input == False: 25 # return False 26 # return second_input 27 if first_input == True: 28 if second_input == True: 29 return Truethe test is still green, because the function returns
True when the conditions are met.
None when the conditions are NOT met, because all functions return None by default, as if they have an invisible line that says return None.
I add a return statement to make it clearer
21def logical_conjunction(first_input, second_input): 22 # return False 23 # return True 24 # if first_input == False: 25 # return False 26 # return second_input 27 if first_input == True: 28 if second_input == True: 29 return True 30 return Nonestill green, because None is grouped as False.
I change None to False in the return statement, to make it clearer
21def logical_conjunction(first_input, second_input): 22 # return False 23 # return True 24 # if first_input == False: 25 # return False 26 # return second_input 27 if first_input == True: 28 if second_input == True: 29 return True 30 # return None 31 return Falsegreen. It now only checks
second_inputiffirst_inputis True.I add bool to the if statements
21def logical_conjunction(first_input, second_input): 22 # return False 23 # return True 24 # if first_input == False: 25 # return False 26 # return second_input 27 # if first_input == True: 28 if bool(first_input) == True: 29 # if second_input == True: 30 if bool(second_input) == True: 31 return True 32 # return None 33 return Falsestill green because
bool(something)returns True if the object in parentheses is grouped as True.Since
bool(True)is the same as True,bool(first_input) == Trueis the same thing asTrue == Truewhenfirst_inputis True, which is a repetition.first_input = True if bool(first_input) == True: if bool(True ) == True: if True == True:I remove
== Truefrom the if statements21def logical_conjunction(first_input, second_input): 22 # return False 23 # return True 24 # if first_input == False: 25 # return False 26 # return second_input 27 # if first_input == True: 28 # if bool(first_input) == True: 29 if bool(first_input): 30 # if second_input == True: 31 # if bool(second_input) == True: 32 if bool(second_input): 33 return True 34 # return None 35 return Falsethe test is still green because
if bool(something)checks ifbool(something)returns Trueif the result of
bool(something)is True thenif bool(something)is the same thing asif Trueif bool(something)is the same asif bool(something) == True
if bool(something) if bool(something) == True if True == True if TrueWhich means I can remove bool
21def logical_conjunction(first_input, second_input): 22 # return False 23 # return True 24 # if first_input == False: 25 # return False 26 # return second_input 27 # if first_input == True: 28 # if bool(first_input) == True: 29 # if bool(first_input): 30 if first_input: 31 # if second_input == True: 32 # if bool(second_input) == True: 33 # if bool(second_input): 34 if second_input: 35 return True 36 # return None 37 return Falsestill 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
this means that
if bool(something) == Trueis the same asif bool(something)is the same asif something.I can use AND to 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 use AND to put the two if statements together
21def logical_conjunction(first_input, second_input): 22 # return False 23 # return True 24 # if first_input == False: 25 # return False 26 # return second_input 27 # if first_input == True: 28 # if bool(first_input) == True: 29 # if bool(first_input): 30 # if first_input: 31 # if second_input == True: 32 # if bool(second_input) == True: 33 # if bool(second_input): 34 # if second_input: 35 if first_input and second_input: 36 return True 37 # return None 38 return Falsegreen.
I add an else clause to make it clearer
21def logical_conjunction(first_input, second_input): 22 # return False 23 # return True 24 # if first_input == False: 25 # return False 26 # return second_input 27 # if first_input == True: 28 # if bool(first_input) == True: 29 # if bool(first_input): 30 # if first_input: 31 # if second_input == True: 32 # if bool(second_input) == True: 33 # if bool(second_input): 34 # if second_input: 35 if first_input and second_input: 36 return True 37 # return None 38 else: 39 return Falsestill green because Python checks if
first_inputis grouped as True when the logical_conjunction function is called. Whenif first_input and second_input:runs,if
first_inputis grouped as False, it leaves the if statement to run the rest of the function -else: return False, which returns False as the output then leaves the function since the return statement is the last thing to run in a functionlogical_conjunction(False, False) -> False └── def logical_conjunction(first_input, second_input): ├── first_input == False ├── second_input == False ├── if first_input and second_input: │ return True └── else: └── return Falselogical_conjunction(False, True ) -> False └── def logical_conjunction(first_input, second_input): ├── first_input == False ├── second_input == True ├── if first_input and second_input: │ return True └── else: └── return Falseif
first_inputis grouped as True, it checks ifsecond_inputis grouped as Trueif
second_inputis grouped as False, it leaves the if statement to run the rest of the function -else: return False, which returns False as the output then leaves the function since the return statement is the last thing to run in a functionlogical_conjunction(True , False) -> False └── def logical_conjunction(first_input, second_input): ├── first_input == True ├── second_input == False ├── if first_input and second_input: │ return True └── else: └── return Falseif
second_inputis grouped as True, it runsreturn True, which returns True as the output then leaves the function since the return statement is the last thing to run in a functionlogical_conjunction(True , True ) -> True └── def logical_conjunction(first_input, second_input): ├── first_input == True ├── second_input == True └── if first_input and second_input: └── return True else: return False
it only checks
second_inputiffirst_inputis True.
conditional expressions
There is a way to write the if statement and else clause on one line instead of four lines. It is called a ternary operator or conditional expression. I add one to the function
21def logical_conjunction(first_input, second_input): 22 # return False 23 # return True 24 # if first_input == False: 25 # return False 26 # return second_input 27 # if first_input == True: 28 # if bool(first_input) == True: 29 # if bool(first_input): 30 # if first_input: 31 # if second_input == True: 32 # if bool(second_input) == True: 33 # if bool(second_input): 34 # if second_input: 35 # if first_input and second_input: 36 # return True 37 # return None 38 # else: 39 # return False 40 return ( 41 True if 42 first_input and second_input 43 else False 44 )the test is still green, because this is the same statement in a different order
return Truecomes first instead of afterif first_input and second_inputfirst_input and second_inputcome next, without theifelsecomes afterfirst_input and second_inputthen False without the return comes after
else
if first_input and second_input: vs return True return True vs if first_input and second_input else: vs else return False vs Falsereturn True if something else Falseis a simpler way to write
if something: return True else: return FalseI can make the conditional expression even simpler, if I remove
True ifandelse False21def logical_conjunction(first_input, second_input): 22 # return False 23 # return True 24 # if first_input == False: 25 # return False 26 # return second_input 27 # if first_input == True: 28 # if bool(first_input) == True: 29 # if bool(first_input): 30 # if first_input: 31 # if second_input == True: 32 # if bool(second_input) == True: 33 # if bool(second_input): 34 # if second_input: 35 # if first_input and second_input: 36 # return True 37 # return None 38 # else: 39 # return False 40 return ( 41 # True if 42 first_input and second_input 43 # else False 44 )still green!
return somethingis a simpler way to write
return True if something else Falsewhich is a simpler way to write
if something: return True else: return FalseI remove the commented lines from
logical_conjunction17def contradiction(first_input, second_input): 18 return False 19 20 21def logical_conjunction(first_input, second_input): 22 return first_input and second_inputI add a variable for
src.truth_table.logical_conjunctionin test_logical_conjunction oftest_binary.py14 def test_logical_conjunction(self): 15 logical_conjunction = ( 16 src.truth_table.logical_conjunction 17 ) 18 self.assertTrue( 19 src.truth_table.logical_conjunction( 20 True, True 21 ) 22 ) 23 self.assertFalse( 24 src.truth_table.logical_conjunction( 25 True, False 26 ) 27 ) 28 self.assertFalse( 29 src.truth_table.logical_conjunction( 30 False, True 31 ) 32 ) 33 self.assertFalse( 34 src.truth_table.logical_conjunction( 35 False, False 36 ) 37 ) 38 39 40# Exceptions seenI use the variable to remove repetition of
src.truth_table.logical_conjunctionfrom the test14 def test_logical_conjunction(self): 15 logical_conjunction = ( 16 src.truth_table.logical_conjunction 17 ) 18 self.assertTrue( 19 # src.truth_table.logical_conjunction( 20 logical_conjunction( 21 True, True 22 ) 23 ) 24 self.assertFalse( 25 # src.truth_table.logical_conjunction( 26 logical_conjunction( 27 True, False 28 ) 29 ) 30 self.assertFalse( 31 # src.truth_table.logical_conjunction( 32 logical_conjunction( 33 False, True 34 ) 35 ) 36 self.assertFalse( 37 # src.truth_table.logical_conjunction( 38 logical_conjunction( 39 False, False 40 ) 41 ) 42 43 44# Exceptions seenthe test is still green.
I remove the commented lines
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)) 22 23 24# Exceptions seenI add a git commit message in the other terminal
git commit -am 'add logical_conjunction'
logical_conjunction also known as and, always returns
first_input and second_inputTrue, if the first input is True and the second input is True
examples of Logical Conjunction
A person can vote, if the inputs are
is the person a citizen?
is the person old enough?
is a citizen
is old enough
can vote
yes
yes
yes
yes
no
no
no
yes
no
no
no
no
A person can get a license, if the inputs are
did the person pass the test?
is the person old enough?
passed test
is old enough
can get license
yes
yes
yes
yes
no
no
no
yes
no
no
no
no
I can bake a cake, if the inputs are
flour?
eggs?
flour
eggs
can bake
yes
yes
yes
yes
no
no
no
yes
no
no
no
no
I am a programmer, if the inputs are
can read code?
can write code?
read
write
is a programmer
yes
yes
yes
yes
no
no
no
yes
no
no
no
no
how did I learn to write without reading?
Multi Factor Authentication to log in, if the inputs are
did the user provide the right password?
did the user provide the MFA code?
right password
right MFA code
log in
yes
yes
yes
yes
no
no
no
yes
no
no
no
no
how did I get the right MFA code without the right password?
I can sell a product, if the inputs are
is there supply?
is there demand?
supply
demand
can sell
yes
yes
yes
yes
no
no
no
yes
no
no
no
no
All of the statements below have the same result as return something because Python groups objects as False or True
return True if
somethingis equal to Trueif something == True: return True else: return Falsereturn True if the result of
bool(something)is equal to Trueif bool(something) == True: return True else: return Falsereturn True if the result of
bool(something)is Trueif bool(something): return True else: return Falsereturn True if the result of
bool(something)is Trueif something: return True else: return Falsereturn True if the result of
bool(something)is Truereturn True if something else False
test_project_second
The truth table for project_second is
first input |
second input |
return |
|---|---|---|
True |
True |
True |
True |
False |
False |
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 project_second with an assertion for the case when the first input is True and the second input is True, to
test_binary.pyfirst input
second input
return
True
True
True
21 self.assertFalse(logical_conjunction(False, False)) 22 23 def test_project_second(self): 24 self.assertTrue( 25 src.truth_table.project_second(True, True) 26 ) 27 28 29# Exceptions seenthe terminal is my friend, and shows AttributeError
AttributeError: module 'src.truth_table' has no attribute 'project_second'because I do not have a definition for the project_second function in
truth_table.py.
GREEN: make it pass
I add project_second to truth_table.py
31def logical_conjunction(first_input, second_input):
32 return first_input and second_input
33
34
35def project_second(first_input, second_input):
36 return True
the test passes. project_second returns True, if the first input is True and the second input is True, just like logical_conjunction
project_second(True , True ) -> True
logical_conjunction(True , True ) -> True
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_project_second in
test_binary.pyfirst input
second input
return
True
False
False
23 def test_project_second(self): 24 self.assertTrue( 25 src.truth_table.project_second(True, True) 26 ) 27 self.assertFalse( 28 src.truth_table.project_second(True, False) 29 ) 30 31 32# Exceptions seenthe terminal is my friend, and shows AssertionError
AssertionError: True is not falsebecause the function returns True and the assertion expects
False, 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
the second input in both cases
I make project_second return
second_inputintruth_table.py25def project_second(first_input, second_input): 26 # return True 27 return second_inputthe test passes. The project_second function returns the second input.
project_second(True , False) -> False project_second(True , True ) -> TrueI remove the commented line
25def project_second(first_input, second_input): 26 return second_inputI add an assertion to test_project_second for the next case, which is if the first input is False and the second input is True, in
test_binary.py23 def test_project_second(self): 24 self.assertTrue( 25 src.truth_table.project_second(True, True) 26 ) 27 self.assertFalse( 28 src.truth_table.project_second(True, False) 29 ) 30 self.assertTrue( 31 src.truth_table.project_second(False, True) 32 ) 33 34 35# Exceptions seenthe test is still green.
project_second(False, True ) -> True project_second(True , False) -> False project_second(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
False
23 def test_project_second(self): 24 self.assertTrue( 25 src.truth_table.project_second(True, True) 26 ) 27 self.assertFalse( 28 src.truth_table.project_second(True, False) 29 ) 30 self.assertTrue( 31 src.truth_table.project_second(False, True) 32 ) 33 self.assertFalse( 34 src.truth_table.project_second(False, False) 35 ) 36 37 38# Exceptions seenstill green.
project_second(False, False) -> False project_second(False, True ) -> True project_second(True , False) -> False project_second(True , True ) -> TrueI add a variable for
src.truth_table.project_second23 def test_project_second(self): 24 project_second = src.truth_table.project_second 25 self.assertTrue( 26 src.truth_table.project_second(True, True) 27 ) 28 self.assertFalse( 29 src.truth_table.project_second(True, False) 30 ) 31 self.assertTrue( 32 src.truth_table.project_second(False, True) 33 ) 34 self.assertFalse( 35 src.truth_table.project_second(False, False) 36 ) 37 38 39# Exceptions seenI use the variable to remove repetition of
src.truth_table.project_secondfrom the test23 def test_project_second(self): 24 project_second = src.truth_table.project_second 25 self.assertTrue( 26 # src.truth_table.project_second(True, True) 27 project_second(True, True) 28 ) 29 self.assertFalse( 30 # src.truth_table.project_second(True, False) 31 project_second(True, False) 32 ) 33 self.assertTrue( 34 # src.truth_table.project_second(False, True) 35 project_second(False, True) 36 ) 37 self.assertFalse( 38 # src.truth_table.project_second(False, False) 39 project_second(False, False) 40 ) 41 42 43# Exceptions seenthe test is still green.
I remove the commented lines
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 31# Exceptions seenI add a git commit message in the other terminal
git commit -am 'add project_second'
project_second always returns the second input. It does not care about the first input, it projects the second input.
examples of Project Second
Binge watching TV, if the inputs are
should I sleep?
do I want to watch one more episode?
sleep?
do I want it?
watch TV
yes
yes
yes
yes
no
no
no
yes
yes
no
no
no
dictatorship, if the inputs are
is voters’ choice?
is dictator’s choice?
voters
dictator
outcome
yes
yes
yes
yes
no
no
no
yes
yes
no
no
no
being sick, if the inputs are
sick before?
sick now?
before
now
sick
healthy
healthy
healthy
healthy
sick
sick
sick
healthy
healthy
sick
sick
sick
my expectation versus reality, if the inputs are
my expectation
reality
expectation
reality
result
True
True
True
True
False
False
False
True
True
False
False
False
test_converse_non_implication
The truth table for converse_non_implication is
first input |
second input |
return |
|---|---|---|
True |
True |
False |
True |
False |
False |
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 converse_non_implication 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
36 self.assertFalse(project_second(False, False)) 37 38 def test_converse_non_implication(self): 39 self.assertFalse( 40 src.truth_table.converse_non_implication( 41 True, True 42 ) 43 ) 44 45 46# Exceptions seenthe terminal is my friend, and shows AttributeError
AttributeError: module 'src.truth_table' has no attribute 'converse_non_implication'because there is no definition for converse_non_implication in
truth_table.pyin thesrcfolder.
GREEN: make it pass
I add converse_non_implication to truth_table.py
25 def project_second(first_input, second_input):
26 return second_input
27
28
29 def converse_non_implication(first_input, second_input):
30 return False
the test passes. converse_non_implication returns False, if the first input is True and the second input is True.
converse_non_implication(True , True ) -> False
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_converse_non_implication of
test_binary.pyfirst input
second input
return
True
False
False
30 def test_converse_non_implication(self): 31 self.assertFalse( 32 src.truth_table.converse_non_implication( 33 True, True 34 ) 35 ) 36 self.assertFalse( 37 src.truth_table.converse_non_implication( 38 True, False 39 ) 40 ) 41 42 43# Exceptions seenthe test is still green. converse_non_implication returns False
if the first input is True and the second input is False
if the first input is True and the second input is True
converse_non_implication(True , False) -> False converse_non_implication(True , True ) -> FalseI add an assertion for the third case, which is if the first input is False and the second input is True
first input
second input
return
False
True
True
30 def test_converse_non_implication(self): 31 self.assertFalse( 32 src.truth_table.converse_non_implication( 33 True, True 34 ) 35 ) 36 self.assertFalse( 37 src.truth_table.converse_non_implication( 38 True, False 39 ) 40 ) 41 self.assertTrue( 42 src.truth_table.converse_non_implication( 43 False, True 44 ) 45 ) 46 47 48# Exceptions seenthe terminal is my friend, and shows AssertionError
AssertionError: False is not truebecause the converse_non_implication function returns False and the assertion expects True.
I add an if statement for this case to the converse_non_implication function in
truth_table.py29def converse_non_implication(first_input, second_input): 30 if first_input == False: 31 return True 32 return Falsethe test passes. converse_non_implication returns
True if the first input is False
False if the above condition is NOT met
because Python checks if
first_inputis equal to False, when the converse_non_implication function is called. Whenif first_input == False:runsif
first_inputis NOT equal to False, it leaves the if statement to run the rest of the function -return False, which returns False as the output then leaves the function since the return statement is the last thing to run in a functionconverse_non_implication(True , True ) -> False └── def converse_non_implication(first_input, second_input): ├── first_input == True ├── second_input == True ├── if first_input == False: │ return True └── return Falseconverse_non_implication(True , False) -> False └── def converse_non_implication(first_input, second_input): ├── first_input == True ├── second_input == False ├── if first_input == False: │ return True └── return Falseif
first_inputis equal to False, it runsreturn True, which returns True as the output then leaves the function since the return statement is the last thing to run in a functionconverse_non_implication(False, True ) -> True └── def converse_non_implication(first_input, second_input): ├── first_input == False ├── second_input == True └── if first_input == False: └── return True return False
I add an assertion for the next case, which is if the first input is False and the second input is False, to test_converse_non_implication in
test_binary.pyfirst input
second input
return
False
False
False
30 def test_converse_non_implication(self): 31 self.assertFalse( 32 src.truth_table.converse_non_implication( 33 True, True 34 ) 35 ) 36 self.assertFalse( 37 src.truth_table.converse_non_implication( 38 True, False 39 ) 40 ) 41 self.assertTrue( 42 src.truth_table.converse_non_implication( 43 False, True 44 ) 45 ) 46 self.assertFalse( 47 src.truth_table.converse_non_implication( 48 False, False 49 ) 50 ) 51 52 53# Exceptions seenthe terminal is my friend, and shows AssertionError
AssertionError: True is not falsebecause the function returned True and the assertion expects False.
I add an if statement for the one case that returns True, to the one in the converse_non_implication function in
truth_table.py29def converse_non_implication(first_input, second_input): 30 if first_input == False: 31 if second_input == True: 32 return True 33 return Falsethe test passes. The converse_non_implication function only checks the second input if the first input is False.
I add bool
29def converse_non_implication(first_input, second_input): 30 # if first_input == False: 31 if bool(first_input) == False: 32 # if second_input == True: 33 if bool(second_input) == True: 34 return True 35 return Falsethe test is still green.
I use Logical Negation (NOT) to write the first if statement in terms of True
29def converse_non_implication(first_input, second_input): 30 # if first_input == False: 31 # if bool(first_input) == False: 32 if not bool(first_input) == True: 33 # if second_input == True: 34 if bool(second_input) == True: 35 return True 36 return Falsestill green.
I remove
== Trueto remove repetition29def converse_non_implication(first_input, second_input): 30 # if first_input == False: 31 # if bool(first_input) == False: 32 # if not bool(first_input) == True: 33 if not bool(first_input): 34 # if second_input == True: 35 # if bool(second_input) == True: 36 if bool(second_input): 37 return True 38 return Falsegreen.
I remove bool
29def converse_non_implication(first_input, second_input): 30 # if first_input == False: 31 # if bool(first_input) == False: 32 # if not bool(first_input) == True: 33 # if not bool(first_input): 34 if not first_input: 35 # if second_input == True: 36 # if bool(second_input) == True: 37 # if bool(second_input): 38 if second_input: 39 return True 40 return Falsestill green, because
Python checks if
first_inputis equal to False whenif first_input == False:runs. I can assume the following substitutionsif 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
Python checks if
(second_input)is equal to True whenif second_input == True:runs. I can assume the following substitutionsif 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
this means that
if bool(something) == Falseis the same asif not bool(something) == Trueis the same asif not bool(something)is the same asif not 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
29def converse_non_implication(first_input, second_input): 30 # if first_input == False: 31 # if bool(first_input) == False: 32 # if not bool(first_input) == True: 33 # if not bool(first_input): 34 # if not first_input: 35 # if second_input == True: 36 # if bool(second_input) == True: 37 # if bool(second_input): 38 # if second_input: 39 if not first_input and second_input: 40 return True 41 return Falsethe test is still 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 be clearer
29def converse_non_implication(first_input, second_input): 30 # if first_input == False: 31 # if bool(first_input) == False: 32 # if not bool(first_input) == True: 33 # if not bool(first_input): 34 # if not first_input: 35 # if second_input == True: 36 # if bool(second_input) == True: 37 # if bool(second_input): 38 # if second_input: 39 if not first_input and second_input: 40 return True 41 else: 42 return Falsestill green because Python checks if
first_inputis grouped as False when the converse_non_implication function is called. Whenif not first_input and second_input:runs,if
first_inputis grouped as True, it leaves the if statement to run the rest of the function -else: return False, which returns False as the output then leaves the function since the return statement is the last thing to run in a functionconverse_non_implication(True , True ) -> False └── def converse_non_implication(first_input, second_input): ├── first_input == True ├── second_input == True ├── if not first_input and second_input: │ return True └── else: └── return Falseconverse_non_implication(True , False) -> False └── def converse_non_implication(first_input, second_input): ├── first_input == True ├── second_input == False ├── if not first_input and second_input: │ return True └── else: └── return Falseif
first_inputis grouped as False, it checks ifsecond_inputis grouped as Trueif
second_inputis grouped as False, it leaves the if statement to run the rest of the function -else: return False, which returns False as the output then leaves the function since the return statement is the last thing to run in a functionconverse_non_implication(False, False) -> False └── def converse_non_implication(first_input, second_input): ├── first_input == False ├── second_input == False ├── if not first_input and second_input: │ return True └── else: └── return Falseif
second_inputis grouped as True, it runsreturn True, which returns True as the output then leaves the function since the return statement is the last thing to run in a functionconverse_non_implication(False, True ) -> True └── def converse_non_implication(first_input, second_input): ├── first_input == False ├── second_input == True └── if not first_input and second_input: └── return True else: return False
it only checks
second_inputiffirst_inputis False.
I use a conditional expression
29def converse_non_implication(first_input, second_input): 30 # if first_input == False: 31 # if bool(first_input) == False: 32 # if not bool(first_input) == True: 33 # if not bool(first_input): 34 # if not first_input: 35 # if second_input == True: 36 # if bool(second_input) == True: 37 # if bool(second_input): 38 # if second_input: 39 # if not first_input and second_input: 40 # return True 41 # else: 42 # return False 43 return ( 44 True if 45 not first_input and second_input 46 else False 47 )green.
if ( vs return True not 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 simpler return statement29def converse_non_implication(first_input, second_input): 30 # if first_input == False: 31 # if bool(first_input) == False: 32 # if not bool(first_input) == True: 33 # if not bool(first_input): 34 # if not first_input: 35 # if second_input == True: 36 # if bool(second_input) == True: 37 # if bool(second_input): 38 # if second_input: 39 # if not first_input and second_input: 40 # return True 41 # else: 42 # return False 43 return ( 44 # True if 45 not first_input and second_input 46 # else False 47 )still green.
converse_non_implication returns
not first_input and second_inputPython replaces
not first_inputwith the logical negation (NOT) offirst_inputwhen it runs
if
first_inputis Falsenot first_input not False Trueif
first_inputis Truenot first_input not True False
this means that in the four cases
if the first input is True and the second input is True, converse_non_implication returns
(not first) and second (not True ) and True False and True # logical_conjunction(False, True) Falseif the first input is True and the second input is False, converse_non_implication returns
(not first) and second (not True ) and False False and False # logical_conjunction(False, False) Falseif the first input is False and the second input is True, converse_non_implication returns
(not first) and second (not False) and True True and True # logical_conjunction(True, True) Trueif the first input is False and the second input is False, converse_non_implication returns
(not first) and second (not False) and False True and False # logical_conjunction(True, False) -> False False
first
not first
second
(not first) and second
True
False
True
False
True
False
False
False
False
True
True
True
False
True
False
False
I add a return statement to show this
29def converse_non_implication(first_input, second_input): 30 # if first_input == False: 31 # if bool(first_input) == False: 32 # if not bool(first_input) == True: 33 # if not bool(first_input): 34 # if not first_input: 35 # if second_input == True: 36 # if bool(second_input) == True: 37 # if bool(second_input): 38 # if second_input: 39 # if not first_input and second_input: 40 # return True 41 # else: 42 # return False 43 return logical_conjunction( 44 logical_negation(first_input), 45 second_input 46 ) 47 return ( 48 # True if 49 not first_input and second_input 50 # else False 51 )the test is still green.
converse_non_implication(False, False) -> False └── logical_conjunction(True , False) -> False converse_non_implication(False, True ) -> True └── logical_conjunction(True , True ) -> True converse_non_implication(True , False) -> False └── logical_conjunction(False, False) -> False converse_non_implication(True , True ) -> False └── logical_conjunction(False, True ) -> FalseI remove the commented lines
29def 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_inputI can use either 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 variable for
src.truth_table.converse_non_implicationintest_binary.py30 def test_converse_non_implication(self): 31 converse_non_implication = ( 32 src.truth_table.converse_non_implication 33 ) 34 self.assertFalse( 35 src.truth_table.converse_non_implication( 36 True, True 37 ) 38 ) 39 self.assertFalse( 40 src.truth_table.converse_non_implication( 41 True, False 42 ) 43 ) 44 self.assertTrue( 45 src.truth_table.converse_non_implication( 46 False, True 47 ) 48 ) 49 self.assertFalse( 50 src.truth_table.converse_non_implication( 51 False, False 52 ) 53 ) 54 55 56# Exceptions seenI use the variable to remove repetition of
src.truth_table.converse_non_implication30 def test_converse_non_implication(self): 31 converse_non_implication = ( 32 src.truth_table.converse_non_implication 33 ) 34 self.assertFalse( 35 # src.truth_table.converse_non_implication( 36 converse_non_implication( 37 True, True 38 ) 39 ) 40 self.assertFalse( 41 # src.truth_table.converse_non_implication( 42 converse_non_implication( 43 True, False 44 ) 45 ) 46 self.assertTrue( 47 # src.truth_table.converse_non_implication( 48 converse_non_implication( 49 False, True 50 ) 51 ) 52 self.assertFalse( 53 # src.truth_table.converse_non_implication( 54 converse_non_implication( 55 False, False 56 ) 57 ) 58 59 60# Exceptions seenthe test is still green.
I remove the commented lines
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)) 38 39 40# Exceptions seen 41# AttributeError 42# TypeError 43# AssertionErrorI add a git commit message in the other terminal
git commit -am 'add converse_non_implication'
Converse Non-Implication always returns
not first_input and second_inputthe Logical Conjunction of, the Logical Negation of the first input, and the second input.
True, if the first input is False and the second input is True.
examples of Converse Non-Implication
crossing the street, if the inputs are
light is green for cars?
light is green for walking?
green for cars?
green for walking?
can I cross the street?
yes
yes
no
yes
no
no
no
yes
yes
no
no
no
do a computer update, if the inputs are
is the computer in use?
is there an update available?
computer in use
update available
do update
yes
yes
no
yes
no
no
no
yes
yes
no
no
no
should I reply to a message?, if the inputs are
is it a group message?
is it one on one from a close friend?
group chat
close friend
reply
yes
yes
no
yes
no
no
no
yes
yes
no
no
no
only give a discount to a new customer with a coupon code, if the inputs are
is already a customer?
does customer have the coupon code?
already customer
has coupon
give discount
yes
yes
no
yes
no
no
no
yes
yes
no
no
no
run the gas generator, if the inputs are
is the house receiving electricity from the grid?
is there fuel in the generator?
grid
fuel
run generator
yes
yes
no
yes
no
no
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
-
first input
second input
return
True
True
False
True
False
False
False
True
True
False
False
False
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
True
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
Logical Conjunction returns
first input
second input
return
True
True
True
True
False
False
False
True
False
False
False
False
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
False
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
and
One logic statement has been written with and, another was written with both and and not.
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 |
code from the chapter
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.