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(
19            logical_conjunction(True, True)
20        )
21        self.assertFalse(
22            logical_conjunction(True, False)
23        )
24        self.assertFalse(
25            logical_conjunction(False, True)
26        )
27        self.assertFalse(
28            logical_conjunction(False, False)
29        )
30
31    def test_project_second(self):
32        project_second = src.truth_table.project_second
33        self.assertTrue(project_second(True, True))
34        self.assertFalse(project_second(True, False))
35        self.assertTrue(project_second(False, True))
36        self.assertFalse(project_second(False, False))
37
38    def test_converse_non_implication(self):
39        converse_non_implication = (
40            src.truth_table.converse_non_implication
41        )
42        self.assertFalse(
43            converse_non_implication(True, True)
44        )
45        self.assertFalse(
46            converse_non_implication(True, False)
47        )
48        self.assertTrue(
49            converse_non_implication(False, True)
50        )
51        self.assertFalse(
52            converse_non_implication(False, False)
53        )
54
55
56# Exceptions seen
57# AttributeError
58# TypeError
59# AssertionError

questions about Binary Operations 1

Questions to think about as I go through the chapter


requirements

truth table: Nullary and Unary Operations

continue the project

  • Make sure you are in the pumping_python folder with pwd in the terminal

    pwd
    

    if the terminal does not show

    .../pumping_python
    

    change directory to the pumping_python folder

  • Once in pumping_python, change directory to the project

    cd truth_table
    

    the terminal shows

    .../pumping_python/truth_table
    
  • I make a new Python file for the tests in the tests directory

    touch tests/test_binary.py
    
    New-Item tests/test_binary.py
    

    the terminal goes back to the command line.

  • I open test_binary.py

  • I add test_binary.py to git for tracking

    git add .
    
  • I run the tests with pytest-watcher

    uv run pytest-watcher . --now
    
  • the 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 when the first input is True and the second input is True, in test_binary.py

    first 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 seen
    

    the 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.py

  • I add AttributeError to the list of Exceptions seen

    13# Exceptions seen
    14# AttributeError
    

GREEN: make it pass


  • I open truth_table.py

  • I add the function to truth_table.py

    13def logical_negation(the_input):
    14    return not the_input
    15
    16
    17def contradiction():
    18    return None
    

    the terminal is my friend, and shows TypeError

    TypeError: contradiction() takes
               0 positional arguments but 2 were given
    

    because 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 seen

    13# Exceptions seen
    14# AttributeError
    15# TypeError
    
  • I add first_input as the name of the first argument in the function signature for contradiction, in truth_table.py

    17# def contradiction():
    18def contradiction(first_input):
    19    return None
    

    the terminal is my friend, and shows TypeError

    TypeError: contradiction() takes
               1 positional argument but 2 were given
    

    because 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_input as the name of the second input in parentheses

    17# def contradiction():
    18# def contradiction(first_input):
    19def contradiction(first_input, second_input):
    20    return None
    

    the test passes because None is grouped as False (the result of bool(None) is False) and the assertion expects 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 False
    

    the test is still green. contradiction returns False, if the first input is True and the second input is True

  • I remove the commented lines

    13def logical_negation(the_input):
    14    return not the_input
    15
    16
    17def contradiction(first_input, second_input):
    18    return False
    
  • I add an assertion for the second case, which is when the first input is True and the second input is False, to test_binary.py

    first 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 seen
    

    the 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

  • I add an assertion for the third case, which is when 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 seen
    

    the 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

  • I add an assertion for the fourth case, which is when the first input is False and the second input is False

    first input

    second input

    return

    False

    False

    False

     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 seen
    

    the test is still green. contradiction returns False

    • if the first input is False

    • if the first input is True

  • I add a variable for src.truth_table.contradiction

     7    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 seen
    
  • I use the variable to remove repetition of src.truth_table.contradiction

     7    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 seen
    

    the test is still green.

  • I remove the commented lines

     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 seen
    
  • I 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?

    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 when the first input is True and the second input is True, in test_binary.py

    first input

    second input

    return

    True

    True

    True

     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        self.assertTrue(
    16            src.truth_table.logical_conjunction(
    17                True, True
    18            )
    19        )
    20
    21
    22# Exceptions seen
    

    the 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


GREEN: make it pass


I add the function 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.


REFACTOR: make it better


  • I add an assertion for the next case, which is when the first input is True and the second input is False, to test_logical_conjunction in test_binary.py

    first 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 seen
    

    the terminal is my friend, and shows AssertionError

    AssertionError: True is not false
    

    because the function returns True and the assertion expects False.

  • I add AssertionError to the list of Exceptions

    27# Exceptions seen
    28# AttributeError
    29# TypeError
    30# AssertionError
    
  • I make the logical_conjunction function in truth_table.py return False

    21def logical_conjunction(first_input, second_input):
    22    # return True
    23    return False
    

    the terminal is my friend, and shows AssertionError

    AssertionError: False is not true
    

    because 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.py

    21def logical_conjunction(first_input, second_input):
    22    # return False
    23    # return True
    24    return second_input
    

    the test passes. logical_conjunction returns

    • False, if the second input is False

    • True, if the second input is True

  • I add an assertion for the third case, which is when the first input is False and the second input is True, to test_logical_conjunction in test_binary.py

    first 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 seen
    

    the terminal is my friend, and shows AssertionError

    AssertionError: True is not false
    

    because 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.py

    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
    

    the test passes. logical_conjunction returns

    • False, if the first input is False

    • the second input if the above condition is NOT met

    because this happens when if first_input == False: runs, Python checks if first_input is equal to False

  • I add an assertion for the last case, which is when the first input is False and the second input is False, to test_logical_conjunction in test_binary.py

    first 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 seen
    

    the test is still green.

  • There is only one case where logical_conjunction returns True, I add an if statement for it in truth_table.py

    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
    

    the test is still green, because the function returns

  • 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 None
    

    still 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 False
    

    green.

  • 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 False
    

    still 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) == True is the same thing as True == True when first_input is True, which is a repetition. I remove == True from 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 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 False
    

    the test is still green because

    • if bool(something) checks if bool(something) returns True

    • if bool(something) == True is the same as if bool(something)

    • if the result of bool(something) is True then if bool(something) is the same thing as if True

  • 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 False
    

    still green because I can assume the following substitutions for if something == True:

    • if the value of something is False

      if something           == True
      if bool(something    ) == True
      if bool(False        ) == True
      if False               == True
      if not True            == True  # change to terms of True
      if not True                     # remove '==True'
      if False
      if something
      
    • if the value of something is True

      if something           == True
      if bool(something    ) == True
      if bool(True         ) == True
      if True                == True  # remove '==True'
      if True
      if something
      

    this means that if bool(something) == True is the same as if bool(something) is the same as if 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 False
    

    green.

  • 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 False
    

    still green because this happens when the logical_conjunction function is called. When if first_input and second_input: runs, Python checks if first_input is grouped as 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 True comes first instead of after if first_input and second_input

    • first_input and second_input come next, without the if

    • else comes after first_input and second_input

    • then False without the return comes after else

    this means that

    return True if something else False
    

    is a simpler way to write

    if something:
        return True
    else:
        return False
    
  • I can make the conditional expression even simpler, if I remove True if and else False

    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    )
    

    still green! This means that

    return something
    

    is a simpler way to write

    return True if something else False
    

    which is a simpler way to write

    if something:
        return True
    else:
        return False
    
  • I remove the commented lines

    17def contradiction(first_input, second_input):
    18    return False
    19
    20
    21def logical_conjunction(first_input, second_input):
    22    return first_input and second_input
    
  • I add a variable for src.truth_table.logical_conjunction in test_logical_conjunction in test_truth_table.py

    14    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 seen
    
  • I use the variable to remove repetition of src.truth_table.logical_conjunction from the test

    14    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 seen
    

    the 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(
    19            logical_conjunction(True, True)
    20        )
    21        self.assertFalse(
    22            logical_conjunction(True, False)
    23        )
    24        self.assertFalse(
    25            logical_conjunction(False, True)
    26        )
    27        self.assertFalse(
    28            logical_conjunction(False, False)
    29        )
    30
    31
    32# Exceptions seen
    
  • I 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_input

  • True, 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

  • Music player goes to the next song or pauses, if the inputs are

    • are headphones connected?

    • has the current song finished playing?

    headphones connected

    current song finished

    play next

    yes

    yes

    yes

    yes

    no

    no

    no

    yes

    no

    no

    no

    no

  • Baking 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

  • 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?

  • selling 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 something is equal to True

    if something == True:
        return True
    else:
        return False
    
  • return True if the result of bool(something) is equal to True

    if bool(something) == True:
        return True
    else:
        return False
    
  • return True if the result of bool(something) is True

    if bool(something):
        return True
    else:
        return False
    
  • return True if the result of bool(something) is True

    if something:
        return True
    else:
        return False
    
  • return True if the result of bool(something) is True

    return 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.py

    first input

    second input

    return

    True

    True

    True

    14    def test_logical_conjunction(self):
    15        logical_conjunction = (
    16            src.truth_table.logical_conjunction
    17        )
    18        self.assertTrue(
    19            logical_conjunction(True, True)
    20        )
    21        self.assertFalse(
    22            logical_conjunction(True, False)
    23        )
    24        self.assertFalse(
    25            logical_conjunction(False, True)
    26        )
    27        self.assertFalse(
    28            logical_conjunction(False, False)
    29        )
    30
    31    def test_project_second(self):
    32        self.assertTrue(
    33            src.truth_table.project_second(True, True)
    34        )
    35
    36
    37# Exceptions seen
    

    the 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 the function 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


REFACTOR: make it better


  • I add an assertion for the second case, which is when the first input is True and the second input is False, to test_project_second in test_binary.py

    first input

    second input

    return

    True

    False

    False

    31    def test_project_second(self):
    32        self.assertTrue(
    33            src.truth_table.project_second(True, True)
    34        )
    35        self.assertFalse(
    36            src.truth_table.project_second(True, False)
    37        )
    38
    39
    40# Exceptions seen
    

    the terminal is my friend, and shows AssertionError

    AssertionError: True is not false
    

    because 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_input in truth_table.py

    25def project_second(first_input, second_input):
    26    # return True
    27    return second_input
    

    the test passes. project_second function returns the second input.

  • I remove the commented line

    25def project_second(first_input, second_input):
    26    return second_input
    
  • I add an assertion to test_project_second for the next case, which is when the first input is False and the second input is True, in test_binary.py

    31    def test_project_second(self):
    32        self.assertTrue(
    33            src.truth_table.project_second(True, True)
    34        )
    35        self.assertFalse(
    36            src.truth_table.project_second(True, False)
    37        )
    38        self.assertTrue(
    39            src.truth_table.project_second(False, True)
    40        )
    41
    42
    43# Exceptions seen
    

    the test is still green.

  • I add an assertion for the last case, which is when the first input is False and the second input is False

    first input

    second input

    return

    False

    False

    False

    31    def test_project_second(self):
    32        self.assertTrue(
    33            src.truth_table.project_second(True, True)
    34        )
    35        self.assertFalse(
    36            src.truth_table.project_second(True, False)
    37        )
    38        self.assertTrue(
    39            src.truth_table.project_second(False, True)
    40        )
    41        self.assertFalse(
    42            src.truth_table.project_second(False, False)
    43        )
    44
    45
    46# Exceptions seen
    

    still green.

  • I add a variable for src.truth_table.project_second

    31    def test_project_second(self):
    32        project_second = src.truth_table.project_second
    33        self.assertTrue(
    34            src.truth_table.project_second(True, True)
    35        )
    36        self.assertFalse(
    37            src.truth_table.project_second(True, False)
    38        )
    39        self.assertTrue(
    40            src.truth_table.project_second(False, True)
    41        )
    42        self.assertFalse(
    43            src.truth_table.project_second(False, False)
    44        )
    45
    46
    47# Exceptions seen
    
  • I use the variable to remove repetition of src.truth_table.project_second from the test

    31    def test_project_second(self):
    32        project_second = src.truth_table.project_second
    33        self.assertTrue(
    34            # src.truth_table.project_second(True, True)
    35            project_second(True, True)
    36        )
    37        self.assertFalse(
    38            # src.truth_table.project_second(True, False)
    39            project_second(True, False)
    40        )
    41        self.assertTrue(
    42            # src.truth_table.project_second(False, True)
    43            project_second(False, True)
    44        )
    45        self.assertFalse(
    46            # src.truth_table.project_second(False, False)
    47            project_second(False, False)
    48        )
    49
    50
    51# Exceptions seen
    

    the test is still green.

  • I remove the commented lines

    31    def test_project_second(self):
    32        project_second = src.truth_table.project_second
    33        self.assertTrue(project_second(True, True))
    34        self.assertFalse(project_second(True, False))
    35        self.assertTrue(project_second(False, True))
    36        self.assertFalse(project_second(False, False))
    37
    38
    39# Exceptions seen
    
  • I 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


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 when the first input is True and the second input is True, to test_binary.py

    first input

    second input

    return

    True

    True

    False

    31    def test_project_second(self):
    32        project_second = src.truth_table.project_second
    33        self.assertTrue(project_second(True, True))
    34        self.assertFalse(project_second(True, False))
    35        self.assertTrue(project_second(False, True))
    36        self.assertFalse(project_second(False, False))
    37
    38    def test_converse_non_implication(self):
    39        self.assertFalse(
    40            src.truth_table.converse_non_implication(
    41                True, True
    42            )
    43        )
    44
    45
    46# Exceptions seen
    

    the 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.py in the src folder.


GREEN: make it pass


I add the function 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.


REFACTOR: make it better


  • I add an assertion for the next case, which is when the first input is True and the second input is False, to test_converse_non_implication in test_binary.py

    first input

    second input

    return

    True

    False

    False

    38    def test_converse_non_implication(self):
    39        self.assertFalse(
    40            src.truth_table.converse_non_implication(
    41                True, True
    42            )
    43        )
    44        self.assertFalse(
    45            src.truth_table.converse_non_implication(
    46                True, False
    47            )
    48        )
    49
    50
    51# Exceptions seen
    

    the 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

  • I add an assertion for the third case, which is when the first input is False and the second input is True

    first input

    second input

    return

    False

    True

    True

    38    def test_converse_non_implication(self):
    39        self.assertFalse(
    40            src.truth_table.converse_non_implication(
    41                True, True
    42            )
    43        )
    44        self.assertFalse(
    45            src.truth_table.converse_non_implication(
    46                True, False
    47            )
    48        )
    49        self.assertTrue(
    50            src.truth_table.converse_non_implication(
    51                False, True
    52            )
    53        )
    54
    55
    56# Exceptions seen
    

    the terminal is my friend, and shows AssertionError

    AssertionError: False is not true
    

    because 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.py

    29def converse_non_implication(first_input, second_input):
    30    if first_input == False:
    31        return True
    32    return False
    

    the test passes. converse_non_implication returns

    • True if the first input is False

    • False if the above condition is NOT met

    because this happens when the converse_non_implication function is called. When if first_input == False: runs, Python checks if first_input is equal to as False

  • I add an assertion for the next case, which is when the first input is False and the second input is False, to test_converse_non_implication in test_binary.py

    first input

    second input

    return

    False

    False

    False

    38    def test_converse_non_implication(self):
    39        self.assertFalse(
    40            src.truth_table.converse_non_implication(
    41                True, True
    42            )
    43        )
    44        self.assertFalse(
    45            src.truth_table.converse_non_implication(
    46                True, False
    47            )
    48        )
    49        self.assertTrue(
    50            src.truth_table.converse_non_implication(
    51                False, True
    52            )
    53        )
    54        self.assertFalse(
    55            src.truth_table.converse_non_implication(
    56                False, False
    57            )
    58        )
    59
    60
    61# Exceptions seen
    

    the terminal is my friend, and shows AssertionError

    AssertionError: True is not false
    

    because 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.py

    29def converse_non_implication(first_input, second_input):
    30    if first_input == False:
    31        if second_input == True:
    32            return True
    33    return False
    

    the test passes.

  • 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 False
    

    the 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 bool(not first_input) == True:
    33        # if second_input == True:
    34        if bool(second_input) == True:
    35            return True
    36    return False
    

    still green.

  • I remove == True to remove repetition

    29def converse_non_implication(first_input, second_input):
    30    # if first_input == False:
    31    # if bool(first_input) == False:
    32    # if bool(not first_input) == True:
    33    if bool(not first_input):
    34        # if second_input == True:
    35        # if bool(second_input) == True:
    36        if bool(second_input):
    37            return True
    38    return False
    

    green.

  • I remove bool

    29def converse_non_implication(first_input, second_input):
    30    # if first_input == False:
    31    # if bool(first_input) == False:
    32    # if bool(not first_input) == True:
    33    # if bool(not 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 False
    

    still green, because

    • when if first_input == False: runs, Python checks if first_input is equal to False. I can assume the following substitutions

      • if the value of something is False

        if something           == False
        if bool(something    ) == False
        if bool(False        ) == False
        if False               == False
        if True                == True  # use equality
        if True                         # remove '== True'
        if not False                    # change to terms of False
        if not something
        
      • if the value of something is True

        if something           == False
        if bool(something    ) == False
        if bool(True         ) == False
        if True                == False
        if False               == True  # use equality
        if False                        # remove '== True'
        if not True                     # change to terms of True
        if not something
        
    • when if second_input == True: runs, Python checks if (second_input) is equal to True. I can assume the following substitutions

      • if the value of something is False

        if something           == True
        if bool(something    ) == True
        if bool(False        ) == True
        if False               == True
        if not True            == True  # change to terms of True
        if not True                     # remove '==True'
        if False
        if something
        
      • if the value of something is True

        if something           == True
        if bool(something    ) == True
        if bool(True         ) == True
        if True                == True  # remove '==True'
        if True
        if something
        

    this means that

    • if bool(something) == False is the same as if bool(not something) == True is the same as if bool(not something) is the same as if not something.

    • if bool(something) == True is the same as if bool(something) is the same as if 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 bool(not first_input) == True:
    33    # if bool(not 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 False
    

    the 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 bool(not first_input) == True:
    33    # if bool(not 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
    

    still green.

  • 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 bool(not first_input) == True:
    33    # if bool(not 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.

  • I remove True if and else False to make the simpler return statement

    29def converse_non_implication(first_input, second_input):
    30    # if first_input == False:
    31    # if bool(first_input) == False:
    32    # if bool(not first_input) == True:
    33    # if bool(not 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_input

    • if first_input is False

      not first_input
      not False
      True
      
    • if first_input is True

      not 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
       False      # logical_conjunction(False, True)
      
    • if 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
       False      # logical_conjunction(False, False)
      
    • if 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
       True       # logical_conjunction(True, True)
      
    • if 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
       False      # logical_conjunction(True, 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 bool(not first_input) == True:
    33    # if bool(not 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.

  • I 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_input
    

    I can use either of these two `return statements`_, the first return statement is the only one that runs in this case, because the return statement is the last thing to run in a function.

  • I add a variable for src.truth_table.converse_non_implication

    38    def test_converse_non_implication(self):
    39        converse_non_implication = (
    40            src.truth_table.converse_non_implication
    41        )
    42        self.assertFalse(
    43            src.truth_table.converse_non_implication(
    44                True, True
    45            )
    46        )
    47        self.assertFalse(
    48            src.truth_table.converse_non_implication(
    49                True, False
    50            )
    51        )
    52        self.assertTrue(
    53            src.truth_table.converse_non_implication(
    54                False, True
    55            )
    56        )
    57        self.assertFalse(
    58            src.truth_table.converse_non_implication(
    59                False, False
    60            )
    61        )
    62
    63
    64# Exceptions seen
    
  • I use the variable to remove repetition of src.truth_table.converse_non_implication

    38    def test_converse_non_implication(self):
    39        converse_non_implication = (
    40            src.truth_table.converse_non_implication
    41        )
    42        self.assertFalse(
    43            # src.truth_table.converse_non_implication(
    44            converse_non_implication(
    45                True, True
    46            )
    47        )
    48        self.assertFalse(
    49            # src.truth_table.converse_non_implication(
    50            converse_non_implication(
    51                True, False
    52            )
    53        )
    54        self.assertTrue(
    55            # src.truth_table.converse_non_implication(
    56            converse_non_implication(
    57                False, True
    58            )
    59        )
    60        self.assertFalse(
    61            # src.truth_table.converse_non_implication(
    62            converse_non_implication(
    63                False, False
    64            )
    65        )
    66
    67
    68# Exceptions seen
    

    the test is still green.

  • I remove the commented lines

    38    def test_converse_non_implication(self):
    39        converse_non_implication = (
    40            src.truth_table.converse_non_implication
    41        )
    42        self.assertFalse(
    43            converse_non_implication(True, True)
    44        )
    45        self.assertFalse(
    46            converse_non_implication(True, False)
    47        )
    48        self.assertTrue(
    49            converse_non_implication(False, True)
    50        )
    51        self.assertFalse(
    52            converse_non_implication(False, False)
    53        )
    54
    55
    56# Exceptions seen
    
  • I 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_input

  • the 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.py and truth_table.py

  • I 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_table

    cd ..
    

    the terminal shows

    .../pumping_python
    

    I am back in the pumping_python directory


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

  • Converse Non-Implication

    first input

    second input

    return

    True

    True

    False

    True

    False

    False

    False

    True

    True

    False

    False

    False

    • returns not first_input and second_input

    • returns True only if first_input is False and second_input is True

    • is the Logical Negation (NOT) of Converse Implication which returns False if first_input is False and second_input is True

  • Project Second

    first input

    second input

    return

    True

    True

    True

    True

    False

    False

    False

    True

    True

    False

    False

    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_input

    • returns True only if first_input is True and second_input is True

    • is the Logical Negation (NOT) of Logical NAND which returns False only if first_input is True and second_input is True

  • Contradiction

    first input

    second input

    return

    True

    True

    False

    True

    False

    False

    False

    True

    False

    False

    False

    False

and

One logic statement has been written with and, another was written both and and not.

return

True, True

True, False

False, True

False, False

name of operation

False

False

False

False

False

contradiction

first and second

True

False

False

False

logical_conjunction

second

True

False

True

False

project_second

(not first) and second

False

False

True

False

converse_non_implication


code from the chapter

Do you want to see all the CODE I typed in this chapter?


what is next?

Would you like to write more tests with bool?


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.