CS50 2019 Lecture 6 – Python

It is Friday afternoon and we are still observing social distancing restrictions and working from home. That said, things are slowly relaxing and more people are out and about. The number of cars on the road has more than tripled since the stay home order started a couple months ago. Please observer social distancing and wear a mask when in public. It is for your well being, your family and friends, your country, and all human beings on this planet.

Currently I am running some tests and writing documentation on some code I wrote earlier during the week. During idle times I am putting together the contents for this post. Hope to be done in the next hour or so. My wife left a minute ago to walk (keeping social distancing) with a neighbor. The day is sunny but rather cold. The temperature is in the upper 40’s.

Every day I read articles from the Communications of the Association for Computing Machinery (ACM) magazines. This morning I read “Reading in the Panopticon- Your Kindle May Be Spying on You, But You Can’t Be Sure” by Stephen B Wicker and Dipayan Ghosh.

The article makes comparisons of the information that is gathered while a person reads books using a Kindle with the Panopticon. The Panopticon was a model for a prison in which guards, staged in the center of a building, were able to observe all inmates all time without them knowing who and when they were being under surveillance.

It first describes which type of information it collects. Most important what is Amazon doing with such information?

It then covers some legal opinions in which people is similar circumstances were able to affirm their First Amendment. That said, today millions of times a day the rights of individuals are ignored in the USA. The European Union has passed laws in which the user may opt out and if not are able to see what is being collected. Then an intelligent decision may be made to opt out or just simply not using or purchasing a Kindle.

In my opinion the Kindle and Amazon are just one case in many where companies collect and use data from individuals without their explicit consent and there is no way to opt out. Imagine, you spend money in a Kindle and you are not able to opt out from surveillance from the manufacturer; only in America!

I periodically experiment with different technologies in an attempt to understand what is available and if possible make changes to protect my privacy. I have installed several web browsers and select different search engines. The amount of ads displayed varies considerably.

It is getting late. My wife got back from her walk. I will finish this post tomorrow morning…

…I am back. Today my wife and I were planning on going to the St. Paul Farmers Market, but due to the venue decided to play it safe and skip it. My son is out an about visiting several Costco stores in order to get some groceries he is in need for.

The motivation for this post was the YouTube video CS50 2019 – Lecture 6 – Python. I like the enthusiasm and knowledge of David Malan, professor at Harvard University. I have watched a few of his classes.

The format for this post will be a list of Python programs in alphabetical order. If you want to get the proper progression and the original Python code, I would suggest watching the video that runs for 01:48:00 hours. I will make some comments on the notes I took while watching the course. Please note that most of the code has been edited. Multiple times I stopped the video and experimented with the software. It took me about eight hours to watch the entire video. I spent a considerable amount of time installing the Python libraries on a Windows 10 machine. I might switch to a Linus computer next time I work with specialized Python libraries. They seem to be developed under Linux so they are friendlier on Linux and Macintosh platforms than Windows.

Some basic set of data structures and functions discussed and available in Python:

Object Definition
Range Sequence of numbers
List Sequence of mutable values
Tuple sequence of immutable values
Dictionary Collection of key/value pairs
Set Collection of unique values

In Python there is no Do-While construct. The simple while with some additional steps seems to work well.

Python supports regular expressions. Some of the ones we will see during this post are:

Symbol Definition
. Any character
.* Zero or more characters
.+ One or more characters
? Optional
^ Start of input
$ End of input

There are many documents on-line that summarize most of the symbols used by regular expressions for Python. That said, I have an old copy of the book “Regular Expressions Pocket Reference” by Tony Stubblebine. Like the fact that it is a book so I can highlight, underline and make notes in it.

The following paragraphs contain additional notes regarding installing different Python libraries to get some of the examples to work. In general, I seldom run into issues obtaining the necessary libraries. It seems that this case was an exception.

How to fix CMake Error in CMakeLists.txt:  Generator NMake Makefiles does not support platform specification, but platform x64 was specified. Found an approach to solve this issue using this link.

After Windows October update, the above method works, but sometimes there are errors like boost error and CMake incompatibilities. To try to address them:

o Download and install CMake msi

o Add CMake into PATH(C:\Program Files\CMake\bin)

o Restart Windows

o pip install dlib or pip install dlib==19.4

Download and install to my machine:

c:\temp\boost_1_73_0.7z

c:\temp\boost_1_73_0

Emotion Recognition using Facial Landmarks, Python, DLib and OpenCV may be found at this link.

Start developing with Visual Studio 2019. I downloaded to my Windows 10 machine the community version because I only had installed VSCode.

Speech Recognition Using Python | Speech to Text Translation in Python | Python Training | Edureka is a YouTube video that I watched to install some software. The video lacked quality.

Speech Recognition Packages:

apiai
assemblyai
Google-cloud-speech
SpeechRecognition
Pocketsphinx
Watson-developer-cloud
Wit

Recognizer class in Speech Recognition basically has instances which are used to recognize speech. Each instance has seven methods to recognize speech from audio source using various APIs.

recognize_bing()
recognize_google()
recognize_google_cloud()
recognize_houndify()
recognize_ibm()
recognize_sphinx()
recognize_wit()

On my machine, VSCode is using the following interpreter:  C:\Users\johnc\AppData\Local\Programs\Python\Python37\python.exe

OK, now we will go over the code snippets and their output collected on the terminal windows of the VSCode IDE. Note that you can run the same code, using the same command, on a command prompt.

# **** to use regular expressions ****
import re

# **** prompt for and get response ****
# s = input("Do you agree? ").upper()
s = input("Do you agree? ")
print(f"s ==>{s}<==\n")

# **** ****
if s[0].upper() == 'Y':
    print("Agreed.")
elif s[0].upper() == 'N':
    print("Not agreed.")
else:
    print("What do you mean?")

# **** ****
if s[0] in ['y']:
    print("Agreed.")
elif s[0] in ['n']:
    print("Not agreed.")
else:
    print("What do you mean?")

# **** with regular expressions ****
if re.search("^y(es)?$", s, re.IGNORECASE):
    print("Agreed.")
elif re.search("^n(o)?$", s, re.IGNORECASE):
    print("Not agreed.")
else:
    print("What do you mean?")

In this program we import the regular expression library for Python.

We may or may not convert the response string to upper case. This was done for simplicity.

The first two tests do not make use of regular expressions. The third does. For a “yes” answer we except a word starting with “y” or “Y” which may be followed by “es” to the end of the string. The treatment of “no” is similar. Any other string will force us display the “What do you mean?” string.

I spent some time experimenting with different regular expressions. Based on the audience you may want to come up with different possibilities and associated regular expressions. In general, the approach is to start simple, test responses and update the regular expression so it is able to catch more specific responses.

PS C:\Users\johnc\workspace0\CS50Python> python agree.py
Do you agree? yes
s ==>yes<== Agreed. Agreed. Agreed. PS C:\Users\johnc\workspace0\CS50Python> python agree.py
Do you agree? no
s ==>no<== Not agreed. Not agreed. Not agreed. PS C:\Users\johnc\workspace0\CS50Python> python agree.py
Do you agree? maybe
s ==>maybe<== What do you mean? What do you mean? What do you mean? PS C:\Users\johnc\workspace0\CS50Python> python agree.py
Do you agree? yea
s ==>yea<== Agreed. Agreed. What do you mean? PS C:\Users\johnc\workspace0\CS50Python>

The previous screen capture illustrates some responses entered by the user and the results obtained by the three approaches. Perhaps in this case a solution not using regular expressions could have worked best.

# **** ****
from sys import argv

# **** main method *****
def main():

    # **** display program arguments ****
    for i in range(len(argv)):
        print(f"argv[{i}]: {argv[i]}")
    print()

    # **** display program arguments (more pythonic way) ****
    for arg in argv:
        print(arg)

# **** call main method ****
main()

In some programming languages (e.g., C, C++, Java) we can pass arguments to the main program at invocation time. We can also do this in Python if we import the proper library.

In Python there is no main method entry point. In this case we define a main method and we call it. Note that this is done to simplify the code and put some order.

In our main method we display the arguments using two approaches. The first one reminds us of the C approach, while the second one is more of a Pythonic way.

PS C:\Users\johnc\workspace0\CS50Python> python argv.py 
argv[0]: argv.py

argv.py
PS C:\Users\johnc\workspace0\CS50Python> python argv.py foo bar
argv[0]: argv.py
argv[1]: foo
argv[2]: bar

argv.py
foo
bar
PS C:\Users\johnc\workspace0\CS50Python>

This example illustrates how simple is to take an image (could be in different formats) and we are able to apply filters to get a desired result. In this case we would like to blur the specified image.

# **** ****
from PIL import Image, ImageFilter

# **** load the image ****
before = Image.open("bridge.jpg")

# **** blur the image ****
after = before.filter(ImageFilter.BLUR)

# **** save the image ****
after.save("out.jpg")

The results follow:

PS C:\Users\johnc\workspace0\CS50Python> python blur.py        
PS C:\Users\johnc\workspace0\CS50Python>

The console capture illustrates calling the blur.py program to blur a specific image. We could have prompted the user to specify an image and then to select the type of filter to use. This could be a nice exercise which I wanted to experiment with. In practice I used the VSCode IDE and selected different filters and personal photos that I have stored in Google.

# **** ****
from sys import exit

# **** main method ****
def main():

    # **** prompt for two strings ****
    s = input("string s: ")
    print(f"s ==>{s}<==") t = input("string t: ") print(f"t ==>{t}<==")

    # **** compare strings ****
    if s == t:
        print(f"s: {s} equals t: {t}")
        exit(0)
    print(f"s: {s} NOT equal to t: {t}")
    exit(-1)

# **** call main ****
main()

In most cases we want the caller of a program to determine if all went well during execution or not. It all started with UNIX. Most (if not all) modern operating systems are able to get a return value from program execution. One can then write a script on the shell and take proper action based on the returned value.

In Python we can do so by importing the sys library and making use of the function exit.

C:\Temp>python compare.py
string s: choco
s ==>choco<== string t: choco t ==>choco<== s: choco equals t: choco C:\Temp>echo %errorlevel%
0

C:\Temp>python compare.py
string s: choco
s ==>choco<== string t: cake t ==>cake<== s: choco NOT equal to t: cake C:\Temp>echo %errorlevel%
-1
C:\Temp>

The program prompts for two strings. If the strings are equal a message is displayed and the program returns 0; otherwise the strings are not equal and the program returns -1.

Note that in this screen capture (which I executed the program on a different computer) uses a command prompt and not the VSCode IDE terminal. After the program executes, we display the returned value. In the first case we display 0 because the strings are equal; while in the second case we display -1 indicating that they were not equal. A similar approach with different commands can be used in Linux.

 **** prompt for x and y ****
x = int(input("x: "))
y = int(input("y: "))

# **** compare x and y ****
if x < y:
    print(f"x: {x} < y: {y}") elif x == y: print(f"x: {x} == y: {y}") else: print(f"x: {x} > y: {y}")

In this example we read in two values. Note the use of the int function. Python threats all input as strings. In this case we need to compare the values as integers.

After the values have been read we compare them and display the appropriate relationship.

S C:\Users\johnc\workspace0\CS50Python> python conditions.py
x: 1
y: 2
x: 1 < y: 2 PS C:\Users\johnc\workspace0\CS50Python> python conditions.py
x: 3
y: 1
x: 3 > y: 1
PS C:\Users\johnc\workspace0\CS50Python> python conditions.py
x: 5
y: 5
x: 5 == y: 5
PS C:\Users\johnc\workspace0\CS50Python>

The output is self explanatory.

# **** cough 3 times ****
print("cough")
print("cough")
print("cough")
print()

# **** cough 3 times ****
print("cough\n" * 3)

# **** cough 3 times ****
for i in range(3):
    print("cough")
print()

# **** define cough method ****
def cough(n):
    for i in range(n):
        print("cough")

# **** cough 3 times ****
# for i in range(3):
#    cough()
cough(3)
print()

# **** define main method ****
def main():
    # for i in range(3):
    #     cough()
    cough(3)

# **** call main method ****
main()

In this example we wish to cough (no pun intended related to the COVID_19 pandemic) three times.

A simple way to do so is by printing three times the required word. A more Pythonic approach is to replicate the text 3 times and have the standard print function display the generated string. A more imperative approach would be to use a loop to print the required string. Similar to the previous code snippet, we could define a method that would take an argument and print the string the specified number of times. Then we call the method with the required argument. Finally we define a main method that calls once the cough method. We have to call the main method so we do it at the end of the code snippet.

S C:\Users\johnc\workspace0\CS50Python> python cough.py     
cough
cough
cough

cough
cough
cough

cough
cough
cough

cough
cough
cough

cough
cough
cough
PS C:\Users\johnc\workspace0\CS50Python>

Whoops, did we have a bug? Five sets of the word repeated three times are displayed. How did this happen? We called the main method once and it only called the cough method once.

In Python, the interpreter processes the file from top to bottom. It sees the first set of instructions and prints the first set of words. It then encounters the instructions to print the string generate with three copies. Next it encounters a method definition. It parses it for correctness but it does not execute it. The next code snippet makes a call to the cough method. That prints a set of lines. We then get to the definition of a method called main. The method is parsed and nothing gets printed. Finally, we read a call to the main method which displays the final set of words.

In general, we want to put all method definitions at the beginning of the source code. When we are ready to start execution, we should define a method that will start and end execution of the code. We can call the method anything we wish (e.g., program, service, main). In C, C++, and Java the entry point must be called main. For consistency and to help developers that are not familiar with Python, it is a good idea to call such method main.

# Find faces in picture
# https://github.com/ageitgey/face_recognition/blob/master/examples/find_faces_in_picture.py

# **** import libraries and modules ****
from PIL import Image
import face_recognition

# **** define main method ****
def main():

    # **** load the jpg file into a numpy array ****
    image = face_recognition.load_image_file("rome_italy.jpg")

    # Find all the faces in the image using the default HOG-based model.
    # This method is fairly accurate, but not as accurate as the CNN model and not GPU accelerated.
    # See also: find_faces_in_picture_cnn.py
    face_locations = face_recognition.face_locations(image, number_of_times_to_upsample=2)

    # **** loop through all detected faces ****
    for face_location in face_locations:

        # **** get and print the location of each face in this image ****
        top, right, bottom, left = face_location
        print(f"top: {top} right: {right} bottom: {bottom} left: {left}")

        # **** show the detected face ****
        face_image = image[top:bottom, left:right]
        pil_image = Image.fromarray(face_image)
        pil_image.show()

# **** call main method ****
main()

This example is more complex than the previous ones. We start by adding a couple libraries. The first one is used to process images and the second to perform face recognition.

We define our main method. We start by loading an image. The name of the image is hard coded. We could easily have prompted for the name to make the program accept other images. In this example I used a selfie of a group of family and friends (including my wife and me), that was taken last year while in a trip to Italy.

The first thing we need is to find all the faces in the picture. Once we have the faces, we loop through the faces and display the rectangles enclosing the recognized faces. In this case the rectangles contain the pixels that appear to represent the face of a person. The face of each person should display in a separate window.

PS C:\Users\johnc\workspace0\CS50Python> python detect.py
top: 405 right: 529 bottom: 566 left: 369
top: 157 right: 763 bottom: 269 left: 652
top: 306 right: 441 bottom: 417 left: 330
top: 308 right: 693 bottom: 442 left: 560
top: 248 right: 946 bottom: 382 left: 812
top: 308 right: 248 bottom: 442 left: 114
top: 256 right: 565 bottom: 368 left: 454
PS C:\Users\johnc\workspace0\CS50Python> 

The output on the IDE console is quite simple. It just displays the coordinates of the rectangles enclosing the pixels that seem to represent the face of a person. In this case the algorithm recognized seven faces. In addition you should see seven windows with the faces of the people in the photograph. Looks that they are happy to be in Rome in a hot afternoon in early fall.

# default dictionary from:
# https://www.mit.edu/~ecprice/wordlist.10000

# **** set of words (this is our dictionary) ****
words = set()

# **** check if this word is in the dictionary ****
def check(word):
    if word.lower() in words:
        return True
    else:
        return False

# **** read from specified file the contents for the dictionary (in lowercase) ****
def load(dictionary):

    # **** open dictionary ****
    file = open(dictionary, "r")

    # **** read the dictionary and populate the set of words ****
    for line in file:
        words.add(line.strip().lower())

    # **** close dictionary ****
    file.close()

    # **** indicate all is well ****
    return True

# **** get the number of words in the dictionary ****
def size():
    return len(words)

# **** free words in dictionary ****
def unload():
    words = set()
    return True

# **** main method ****
def main():

    # **** get the name for the dictionary ****
    dictionary = input("dictionary (blank to load default): ")

    # **** dictionary not specified (use default one) ****
    if dictionary == "":
        dictionary = "dict.txt"
    print(f"dictionary ==>{dictionary}<==")

    # **** load the dictionary ****
    if not load(dictionary):
        print(f"load dictionary: {dictionary} failed !!!")
        exit(-1)

    # **** get the number of words in the dictionary ****
    count = size()
    print(f"dictionary has {count} words")

    # **** loop looking up words in the dictionary ****
    while True:
        
        # **** prompt for word to check ****
        word = input("word (blank to exit): ")

        # **** check if we are done (exit loop) ****
        if word == "":
            break

        # **** check the word ****
        if check(word):
            print(f"found word: {word}")
        else:
            print(f"word: {word} NOT found !!!")

    # **** unload the dictionary ****
    if not unload():
        print(f"unload dictionary: {dictionary} failed !!!")
        exit(-1)

# **** call main method ****
main()

In this example we will load a dictionary of English words. The URI for the dictionary is displayed at the top of the Python file. The actual set of words is also available in the GitHub repository.

We will represent our dictionary with a set of words. The dictionary will only allow us to perform spelling checking operations. We will not associate a word with a definition.

The check method looks up a word in the dictionary. If found it returns True; otherwise it returns False. Before we can check words we need to load the dictionary from a file. The load method does this by accepting as an argument the name of a list of valid English words.

To load the dictionary we open the file, loop reading all words and add them one by one to the set in our program.  Note that we make sure all words are in lower case. We then close the file and return True to indicate to the caller that all went well. In production code we might throw an exception.

The size method allows us to get the number of words in our dictionary once it has been loaded.

The unload method releases the set of words in the dictionary. I suggest experimenting with this method by calling it from different places in the main method.

The main method puts all things together. We ask for a name for the dictionary to use. If the user does not specify a name, we specify our default dictionary.

We load the dictionary and check if all is well so far. We get and display the number of words in our dictionary.

We then enter a loop prompting for a word to check. We display the results. If the user does not enter a word, we exit the loop.

We then unload our dictionary from memory and return from the main method. Since there are no more instructions our program exits.

PS C:\Users\johnc\workspace0\CS50Python> python dictionary.py
dictionary (blank to load default):
dictionary ==>dict.txt<== dictionary has 10000 words word (blank to exit): hello found word: hello word (blank to exit): world found word: world word (blank to exit): cake found word: cake word (blank to exit): kake word: kake NOT found !!! word (blank to exit): PS C:\Users\johnc\workspace0\CS50Python>

In this case we do not specify a name for the dictionary to load, so the program uses the default one. The number of words should be 10,000 if you selected the default dictionary file.

We loop entering words. The first three words are valid. The fourth does not exist. In a production environment we could have displayed similar words to “kake” (i.e., “cake”, “bake”) or use NLP in AI and autocorrect. Such operation would require the context in which the word was misspelled.

# **** ****
from sys import argv, exit

# **** main method ****
def main():

    # **** sanity check ****
    if len(argv) < 2:
        print("missing command-line argument")
        exit(1)

    # **** display list of names ****
    print("Hello", end="")
    for i in range(1, len(argv)):

        # **** skip program name ****
        # if i == 0:
        #     continue
        
        # **** display separator ****
        if i == 1:
            print(" ", end='')
        elif i == len(argv) - 1:
            print(" and ", end='')
        else:
            print(", ", end='')

        # **** display name ****
        print(f"{argv[i].capitalize()}", end='')

    # **** all done ****
    exit(0)

# **** call main method ****
main()

We start by importing a couple Python libraries. We then define a main method. We check if the caller specified at least one argument to the Python program when it was invoked. By the comments on the code, it seems that the user should specify one or more names as arguments.

We start by displaying “Hello” followed by the names that were entered as arguments. In this example we are not validating if the words are names, we could enter any valid or invalid word.

After the loop we exit the program (not the main method) with a status of 0 indicating all went well. If we just return from the main method, by default, Python would exit the code with a value of zero.

PS C:\Users\johnc\workspace0\CS50Python> python exit.py
missing command-line argument
PS C:\Users\johnc\workspace0\CS50Python> python exit.py peter
Hello Peter
PS C:\Users\johnc\workspace0\CS50Python> python exit.py peter paul
Hello Peter and Paul
PS C:\Users\johnc\workspace0\CS50Python> python exit.py peter paul mary
Hello Peter, Paul and Mary
PS C:\Users\johnc\workspace0\CS50Python>

We invoke the program without additional arguments. We then invoke the program with additional arguments. The arguments are valid English names. Note that the program spaces the names properly according to English grammar.

# **** print string ****
print("hello, world !!!")

# **** prompt for name and print it ****
name = input("What is your name? ")
print("Hello,", name, "!!!")
print("Hello. " + name + " !!!")
print(f"Hello, {name} !!!")
print()

# **** initialize and increment counter ****
counter = 0
print(f"counter: {counter}")
counter = counter + 1
print(f"counter: {counter}")
counter += 1
print(f"counter: {counter}")
print()

# **** compare integers ****
x = 8
y = 7
if x < y:
    print(f"x: {x} < y: {y}") elif x == y: print(f"x: {x} == y: {y}") else: print(f"x: {x} > y: {y}")
print()

# **** loop forever but exit loop at break ****
while True:
    print("hello, world !!!")
    break
print()

# **** loop until condition is met ****
i = 0
while i < 3:
    print(f"cough i: {i}")
    i += 1
print()

# **** loop for each element in the list ****
for i in [1, 2, 3]:
    print(f"cough i: {i}")
print()

# **** loop for each element in the list ****
for i in ['potato', 'carrot', 'letuce']:
    print(f"cough i: {i}")
print()

# **** loop for the specified range ****
for i in range(3):
    print(f"cough i: {i}")
print()

This program is an introduction to Python syntax. We start by printing the simple and common “hello, world !!!” phrase. We then prompt for the name of the user and display the same string in multiple ways. I prefer to use the format string (the one in which the string is preceded by a lower case ‘f’).

We specify an integer as a counter and increment the value a couple times. We define two integers and display their relation. We could have prompted for the integers but in this case we hard coded the value.

Next we define an infinite loop that displays a phrase. We break out of the loop after it printed the phrase once. In the next snippet we set a value in a variable and then enter a loop that displays the word ‘cough’ three times. This is accomplished by incrementing the value of i inside the loop. Failure to do so would result in an infinite loop.

In the next snippet we use a list of values and loop once per value displaying a string. We repeat the process using a different list. Note that all three examples use different lists. The count is not associated with the values in the list but with the number of elements.

In the next snippet we use the function range which generates numbers in the specified range. In this case 0, 1, and 2.

PS C:\Users\johnc\workspace0\CS50Python> python hello.py
hello, world !!!
What is your name? john
Hello, john !!!
Hello. john !!!
Hello, john !!!

counter: 0
counter: 1
counter: 2

x: 8 > y: 7

hello, world !!!

cough i: 0
cough i: 1
cough i: 2

cough i: 1
cough i: 2
cough i: 3

cough i: potato
cough i: carrot
cough i: letuce

cough i: 0
cough i: 1
cough i: 2

PS C:\Users\johnc\workspace0\CS50Python>

Not much to add at this point. The first string is displayed. We then prompt for the name of the user. I entered my name in lower case and the program displays it as I entered it. It seems that the output matches expectations.

# **** prompt for age ****
age = int(input("What's your age? "))

# **** display age in days ****
print(f"You are at least {age * 365} days old.")

In this example we request the age of the user. We enclose the input function with the function int. The reason as we saw in an earlier example it to convert the string entered by the user into an integer. In production we should check if the string represents a number and if the number is in a valid expected range. For example, the age cannot be a negative number or an integer larger than 120.

PS C:\Users\johnc\workspace0\CS50Python> python int.py  
What's your age? 10
You are at least 3650 days old.
PS C:\Users\johnc\workspace0\CS50Python>

We run the program and enter an age. In this case we enter 10 which if we multiply by 365 it produces the expected value. Note that our approach did not check for date of birth. We would need the date to make sure we take into account leap years (https://en.wikipedia.org/wiki/Leap_year). This is why the program states that the number of days is “at least” the computer result, which is a correct assumption given what the prompt stated.

# **** print question marks ****
for i in range(4):
    print("?", end="")
print("\n")

# **** print question marks ****
print("?" * 4)
print()

# **** print bricks ****
for i in range(3):
    print("#")
print()

# **** print bricks ****
print("#\n" * 3, end="")
print()

# **** print a wall ****
for i in range(4):
    for j in range(4):
        print("#", end="")
    print()
print()

This example attempts to generate a component of a scene in a Mario game using a command prompt. The purpose is to display a set of horizontal and then vertical characters. We then display an array symbolizing a wall in the Mario game. Disclaimer: I am not into video games.

PS C:\Users\johnc\workspace0\CS50Python> python mario.py
????

????

#
#
#

#
#
#

####
####
####
####

PS C:\Users\johnc\workspace0\CS50Python>

The output is as expected. We used different formats to achieve the same results.

# **** ****
from sys import exit

# **** main method ****
def main():

    # **** list of names ****
    names = ["emma", "Rodrigo", "brian", "JOHN", "david", "james"]
    print(f"names: {names}\n")
    
    # **** prompt for name ****
    name = input("name to search in list: ")

    # **** check if we are done ****
    if name == "":
        exit(0)

    # **** search for the specified name in the list (ignore spelling) ****
    # found = False
    # for n in names:
    #     if (name.capitalize() == n.capitalize()):
    #         found = True
    #         print(f"found {name} in list")
    #         break

    # # **** ****
    # if not found:
    #     print(f"{name} NOT in list :o(")
    #     exit(-1)
    # else:
    #     exit(0)

    # **** search for the specified name in the list (must match spelling)****
    if name in names:
        print(f"found {name} in list :o)")
        exit(0)
    else:
        print(f"{name} NOT in list :o(")
        exit(-1)

# **** call main method ****
main()

# **** display a message (should not display) ****
print("bye bye")

In this example we import from the library sys the class exit. We define a main method. The method defines a list of names. We prompt for a name. If none is entered we exit the program.

You can see that we used two approaches to look for the name in the list. The first has been commented out. The second approach is the Pythonic way of searching a list. Note that if we find the name we exit the program with a 0; otherwise it exits with a -1.

Note that the Python program exists inside the main method. The message following the main method is never executed.

PS C:\Users\johnc\workspace0\CS50Python> python names.py
names: ['emma', 'Rodrigo', 'brian', 'JOHN', 'david', 'james']

name to search in list: emma
found emma in list :o)
PS C:\Users\johnc\workspace0\CS50Python> python names.py
names: ['emma', 'Rodrigo', 'brian', 'JOHN', 'david', 'james']

name to search in list: rodrigo
rodrigo NOT in list :o(
PS C:\Users\johnc\workspace0\CS50Python> python names.py
names: ['emma', 'Rodrigo', 'brian', 'JOHN', 'david', 'james']

name to search in list: Rodrigo
found Rodrigo in list :o)
PS C:\Users\johnc\workspace0\CS50Python> python names.py
names: ['emma', 'Rodrigo', 'brian', 'JOHN', 'david', 'james']

name to search in list: david
found david in list :o)
PS C:\Users\johnc\workspace0\CS50Python>

We display the names and then prompt the user for a name in the list. This is an example of a selection. By not entering the name exactly as displayed, the program fails to find the name in the list. Also note that as we expected, the “bye bye” string is never displayed because the program ends when we call the exit method. You should experiment by allowing the user to type the names any way they wish and having the name be selected if in the list.

# **** ****
import time

# **** how to exit ****
print("enter ctrl-c to exit\n")

# **** loop multiplying the number by 2 ****
i = 1
while True:
    print(i)
    time.sleep(0.25)
    i *= 2

We import the time library because we need to slow down the program to be able to read the values as they are created and displayed. We specify the way to exit the program and we enter an infinite loop. On each pass we display the value of ‘I’ and sleep for a quarter of a second. We then increment the value by multiplying it by 2.

PS C:\Users\johnc\workspace0\CS50Python> python overflow.py
enter ctrl-c to exit

1
2
4
8
16
32
64
128
256
512
1024
2048
4096
8192
16384
32768
65536
131072
262144
524288
1048576
2097152
4194304
8388608
16777216
33554432
67108864
134217728
268435456
536870912
1073741824
2147483648
4294967296
8589934592
17179869184
34359738368
68719476736
137438953472
274877906944
549755813888
1099511627776
2199023255552
4398046511104
8796093022208
17592186044416
35184372088832
70368744177664
140737488355328
281474976710656
562949953421312
1125899906842624
2251799813685248
4503599627370496
9007199254740992
18014398509481984
36028797018963968
72057594037927936
144115188075855872
288230376151711744
576460752303423488
1152921504606846976
2305843009213693952
4611686018427387904
9223372036854775808
18446744073709551616
36893488147419103232
73786976294838206464
147573952589676412928
295147905179352825856
590295810358705651712
1180591620717411303424
2361183241434822606848
4722366482869645213696
9444732965739290427392
18889465931478580854784
37778931862957161709568
75557863725914323419136
151115727451828646838272
302231454903657293676544
604462909807314587353088
1208925819614629174706176
2417851639229258349412352
4835703278458516698824704
9671406556917033397649408
19342813113834066795298816
38685626227668133590597632
77371252455336267181195264
154742504910672534362390528
309485009821345068724781056
618970019642690137449562112
1237940039285380274899124224
2475880078570760549798248448
4951760157141521099596496896
9903520314283042199192993792
19807040628566084398385987584
39614081257132168796771975168
79228162514264337593543950336
158456325028528675187087900672
316912650057057350374175801344
633825300114114700748351602688
1267650600228229401496703205376
2535301200456458802993406410752
5070602400912917605986812821504
10141204801825835211973625643008
20282409603651670423947251286016
40564819207303340847894502572032
81129638414606681695789005144064
162259276829213363391578010288128
324518553658426726783156020576256
649037107316853453566312041152512
1298074214633706907132624082305024
2596148429267413814265248164610048
5192296858534827628530496329220096
10384593717069655257060992658440192
20769187434139310514121985316880384
41538374868278621028243970633760768
83076749736557242056487941267521536
166153499473114484112975882535043072
332306998946228968225951765070086144
664613997892457936451903530140172288
1329227995784915872903807060280344576
Traceback (most recent call last):
  File "overflow.py", line 11, in <module>
    time.sleep(0.25)
KeyboardInterrupt
PS C:\Users\johnc\workspace0\CS50Python> 

The output starts displaying the expected sequence. All is good. As the program continues we note that the integers keep on growing. If we would have used C, C++, or Java (just to mention a few) we would have ran into an overflow when the integer exceeded the capacity based on the definition of an integer. In Python the numbers would increase until the program runs out of memory or buffer space to display the string representation. That is a great feature of Python that makes it very attractive for statistic and machine learning work.

# **** ****
from sys import exit

# **** main method ****
def main():

    # **** dictionary (associative array) ****
    people = {
        "EMMA" : "617-555-0100",
        "RODRIGO" : "617-555-0101",
        "BRIAN" : "617-555-0102",
        "DAVID" : "617-555-0103",

        "JAMES" : "617-007-0071",
        "JOHN" : "617-007-0072"
    }
    print(f"people: {people}\n")

    # **** prompt for a name ****
    name = input("name: ").upper()
    print(f"looking for name: {name.capitalize()}")

    # **** search for the name in people ****
    if name in people:
        print(f"found: {name.capitalize()} phone: {people[name.upper()]}")

        phone = people.get(name)
        print(f"found: {name.capitalize()} phone: {phone}")

        # **** done ****
        exit(0)
    
    # **** name not found ****
    print(f"name: {name.capitalize()} NOT found")
    exit(-1)

# **** call main method ****
main()

In this case we define a main method. We define a dictionary which associates a name in upper case with a phone number. Our dictionary has defined six entries. For ease of use we display the contents of the dictionary.

We then prompt the user to enter a name. For ease we convert the name entered by the user to upper case. We search for the name and display it in a nicer way followed by the phone number. If we do not find the name we display a message. In either case we exit the program. Note that if the name is found we exit with 0; otherwise we exit with a -1 to indicate something went wrong. By convention, in most (never say all) operating systems, an exit code of 0 represents all is well, a negative number represents a failure and a positive number represents a warning.

PS C:\Users\johnc\workspace0\CS50Python> python phonebook.py
people: {'EMMA': '617-555-0100', 'RODRIGO': '617-555-0101', 'BRIAN': '617-555-0102', 'DAVID': '617-555-0103', 'JAMES': '617-007-0071', 'JOHN': '617-007-0072'}

name: EMMA
looking for name: Emma
found: Emma phone: 617-555-0100
found: Emma phone: 617-555-0100
PS C:\Users\johnc\workspace0\CS50Python> python phonebook.py
people: {'EMMA': '617-555-0100', 'RODRIGO': '617-555-0101', 'BRIAN': '617-555-0102', 'DAVID': '617-555-0103', 'JAMES': '617-007-0071', 'JOHN': '617-007-0072'}

name: JOHN
looking for name: John
found: John phone: 617-007-0072
found: John phone: 617-007-0072
PS C:\Users\johnc\workspace0\CS50Python> python phonebook.py
people: {'EMMA': '617-555-0100', 'RODRIGO': '617-555-0101', 'BRIAN': '617-555-0102', 'DAVID': '617-555-0103', 'JAMES': '617-007-0071', 'JOHN': '617-007-0072'}

name: john
looking for name: John
found: John phone: 617-007-0072
found: John phone: 617-007-0072
PS C:\Users\johnc\workspace0\CS50Python> python phonebook.py
people: {'EMMA': '617-555-0100', 'RODRIGO': '617-555-0101', 'BRIAN': '617-555-0102', 'DAVID': '617-555-0103', 'JAMES': '617-007-0071', 'JOHN': '617-007-0072'}

name: Bond
looking for name: Bond
name: Bond NOT found
PS C:\Users\johnc\workspace0\CS50Python> python phonebook.py
people: {'EMMA': '617-555-0100', 'RODRIGO': '617-555-0101', 'BRIAN': '617-555-0102', 'DAVID': '617-555-0103', 'JAMES': '617-007-0071', 'JOHN': '617-007-0072'}

name: james bond
looking for name: James bond
name: James bond NOT found
PS C:\Users\johnc\workspace0\CS50Python>

The screen capture seems to provide the expected results. Note that in this case we did not display what the operating system (OS) collected as the exit code for the program. We showed this in a previous example. The method used depends on the OS you are using. You can always use Google to find the required format for your OS. In this post we are using Windows 10.

# **** ****
import csv

# **** main method ****
def main():

    # **** prompt for a name and number ****
    name = input("name: ").capitalize()
    number = input("number: ")
    print(f"name: {name} number: {number}")

    # **** open the phonebook file ****
    phoneBook = "phonebook.csv"
    with open(phoneBook, "a", newline="") as file:
        
        # **** writer for csv file ****
        writer = csv.writer(file)

        # **** write the name and number to the csv file ****
        writer.writerow((name, number))

    # **** close the file ****
    # file.close()

# **** call main method ****
main()

In this example we will collect from the user a name and a phone number. Without additional checks, we will open a CSV file and append a new row with the specified information. When done the CSV file will be closed. Note that the operations will be defined in the main method. The Python file will call the main method for execution.

PS C:\Users\johnc\workspace0\CS50Python> python phonebook1.py
name: Jones
number: 123-123-1234
name: Jones number: 123-123-1234
PS C:\Users\johnc\workspace0\CS50Python> 

We specify a name and a phone number. We display the information we are about to append to the CSV file.

name,number
James,123-456-7890
John,612-598-5825
Carmen,612-598-5820
Penny,123-111-2222
Pussy,123-444-4444
Peter,999-000-9999
Jimmy,111-111-1111
Dick,222-222-2222
Bond,777-777-7777
Galore,123-444-4445
Jones,123-123-1234

The last screen capture shows the contents of the CSV file after the new record was appended.

# **** prompt user and loop until positive number is entered ****
def get_positive_int():

    # **** loop until condition is satisfied ****
    while True:

        # **** prompt user ****
        n = int(input("positive integer: "))

        # **** check if done ****
        if n > 0:
            break;
    
    # **** return positive integer ****
    return n

# **** main method ****
def main():

    # **** prompt for and return a positive integer ****
    i = get_positive_int()
    print(f"i: {i}")

# **** call main method ****
main()

This Python file is going to invoke the main method. The main method is going to use the get_positive_int method to request an integer from the user. The get_positive_int method is implemented as a while loop. The program displays a prompt and gets back an integer value. If the number is positive, the loop exits. The method returns the positive number.

PS C:\Users\johnc\workspace0\CS50Python> python positive.py  
positive integer: -9
positive integer: -3
positive integer: 0
positive integer: 1
i: 1
PS C:\Users\johnc\workspace0\CS50Python>

We start the program and it prompts for a positive integer. We try three times with incorrect values. On the fourth attempt we enter a positive integer. The program displays it and exits.

# Identify and draw box on a specified person
# https://github.com/ageitgey/face_recognition/blob/master/examples/identify_and_draw_boxes_on_faces.py

# **** imports ****
import face_recognition
import numpy as np
from PIL import Image, ImageDraw

# **** message ****
print("please wait ...")

# **** load a sample picture and learn how to recognize it ****
known_image = face_recognition.load_image_file("carmen.jpg")
encoding = face_recognition.face_encodings(known_image)[0]

# **** load an image with unknown faces ****
unknown_image = face_recognition.load_image_file("rome_italy.jpg")

# **** find all the faces and face encodings in the unknown image ****
face_locations = face_recognition.face_locations(unknown_image)
face_encodings = face_recognition.face_encodings(unknown_image, face_locations)

# **** convert the image to a PIL-format image so that we can draw on top of it with the Pillow library ****
# see http://pillow.readthedocs.io/ for more about PIL/Pillow
pil_image = Image.fromarray(unknown_image)

# **** create a Pillow ImageDraw Draw instance to draw with ****
draw = ImageDraw.Draw(pil_image)

# **** loop through each face found in the unknown image ****
for (top, right, bottom, left), face_encoding in zip(face_locations, face_encodings):

    # **** see if the face is a match for the known face(s) ****
    matches = face_recognition.compare_faces([encoding], face_encoding)

    # **** use the known face with the smallest distance to the new face ****
    face_distances = face_recognition.face_distance([encoding], face_encoding)
    best_match_index = np.argmin(face_distances)
    
    # **** draw a box around the face using the Pillow module (if needed) ****
    if matches[best_match_index]:
        draw.rectangle(((left - 20, top - 20), (right + 20, bottom + 20)), outline=(255, 0, 0), width=20)

# **** remove the drawing library from memory as per the Pillow docs ****
del draw

# **** message ****
print("... done !!!")

# **** display the resulting image ****
pil_image.show()

This is probably the coolest program in this post. We start by importing some libraries.

We then load an image that should contain a clear picture of the face of a person. The name of the file is hard coded.

We then load an image with multiple people. The name of the image is also hard coded into the program.

We get the locations of all faces and extract the actual faces.

We then get a version of the image in a format that we can use for display.

Next we enter a loop and attempt to match the image of the face of the person of interest against all the faces in the group image. We get numeric representations. We then check the current image against the best match. For the best match we draw a rectangle around the face in the group image.

After the loop we delete the drawing. We display a message and show the group image with the rectangle.

PS C:\Users\johnc\workspace0\CS50Python> python recognize.py
please wait ...
... done !!!
PS C:\Users\johnc\workspace0\CS50Python> 

The program displays a message when it starts operations. When done, it displays a message. What is more important is that the group image will display with the face of the selected person displayed with a green rectangle around it. If you use the sample images as illustrated in the code, the face of Carmen will be displayed with a rectangle.

# **** main method ****
def main():

    # **** populate list of scores ****
    # scores = []
    # scores.append(72)
    # scores.append(73)
    # scores.append(33)

    scores = [72, 73, 33]

    print(f" scores: {scores}")

    # **** compute the average score (imperative way) ****
    average = 0
    for i in range(len(scores)):
        average += scores[i]
    average /= len(scores)

    print(f"average: {average}\n")

    # *** compute the average score (pythonic way) ****
    print(f"sum(scores): {sum(scores)}")
    print(f"len(scores): {len(scores)}")
    
    print(f"    average: {sum(scores) / len(scores)}")

# **** call main method ****
main()

In this last example, we declare a list with three values. The contents of the list are then displayed. We then compute the average using two different approaches.

S C:\Users\johnc\workspace0\CS50Python> python scores.py
 scores: [72, 73, 33]
average: 59.333333333333336

sum(scores): 178
len(scores): 3
    average: 59.333333333333336
PS C:\Users\johnc\workspace0\CS50Python>

In this last screen capture we are able to see that the two approaches produced the same result. The second approach seems to be simpler and shorter.

# **** ****
import speech_recognition as sr

# **** speech response method ****
def speechResponse(words):
    if "hello" in words:
        print("Hello to you too!")
    elif "how are you" in words:
        print("I am well, thanks!")
    elif "goodbye" in words:
        print("Goodbye to you too!")
    else:
        print("Huh?")

# **** main method ****
def main():

    # **** ****
    r = sr.Recognizer()
    with sr.Microphone() as source:
        print("say something: ")
        audio = r.listen(source)

    # **** ****
    print("Google Speech Recognition thinks you said: ")
    print(r.recognize_google(audio))

# **** call main method ****
main()

# # **** prompt for some words ****
# words = input("say something: ").lower()
# print(f"words: {words}\n")

# # **** call speechResponse method ****
# speechResponse(words)

In this last source code we start by importing a speech recognition library.  We define a method speechResponse that will be used to respond to the words uttered by the user. Such words are passed provided in the argument.

The main method creates a recognizer. We display a prompt to get a response from the user. The response is captured by the microphone. I happen to have an Azure Kinect camera attached to my computer. The same programs works well on a different Windows machine using a Logitech C922 Pro Stream Webcam camera.

We display what the user uttered and return.

There is additional code following the main method. Such code has been commented out. When dealing with new libraries is always good idea to spend some time experimenting with them to fully understand how they work.

PS C:\Users\johnc\workspace0\CS50Python> python speech.py 
say something:
Google Speech Recognition thinks you said:
hello Google
PS C:\Users\johnc\workspace0\CS50Python> python speech.py
say something:
Google Speech Recognition thinks you said:
hello world how are you
PS C:\Users\johnc\workspace0\CS50Python> python speech.py
say something:
Google Speech Recognition thinks you said:
my name is John canessa
PS C:\Users\johnc\workspace0\CS50Python> python speech.py
say something:
Google Speech Recognition thinks you said:
That's all folks
PS C:\Users\johnc\workspace0\CS50Python> 

The output shows how accurate the Google speech recognition module is. Your mileage will change depending on multiple factors i.e., noise, microphone location, and human accent. I like the last sentence in which the system recognized “that’s” over “that is”.

# **** prompt for the name ****
s = input("please enter your name: ")

# **** display hello message ****
print(f"hello, {s.capitalize()}")

In this example we go back to processing written input and display it in a nicer way.

PS C:\Users\johnc\workspace0\CS50Python> python string0.py
please enter your name: john
hello, John
PS C:\Users\johnc\workspace0\CS50Python> python string0.py
please enter your name: John Canessa
hello, John canessa
PS C:\Users\johnc\workspace0\CS50Python>

I can enter my name in lower or uppercase and the output would always be capitalized. If you experiment with this example you may found a better way to display a name. Hint: check the title method.

# **** main method ****
def main():

    # **** prompt and display string ****
    s = input("input: ")
    print(f"s ==>{s}<==") # **** display the string character by character **** print("output ==>", end="")
    for i in range(len(s)):
        print(s[i], end="")
    print("<==") # **** a more pythonic approach **** print("output ==>", end="")
    for c in s:
        print(c, end="")
    print("<==")

# **** call main method ****
main()

In this example we prompt the user to enter a string. We then display it character by character. The two approaches seem to produce the same result. The second is considered more Pythonic. Note that both approaches take the same number of lines.

PS C:\Users\johnc\workspace0\CS50Python> python string1.py
input: hello world
s ==>hello world<== output ==>hello world<== output ==>hello world<== PS C:\Users\johnc\workspace0\CS50Python>

This last screen capture shows that both approaches seem to return the same result.

# **** swap method ****
def swap(x, y):
    y, x = x, y
    return x, y

# **** main method ****
def main():

    # **** define two variables ****
    x = 1
    y = 2
    print(f"[0] x: {x} y: {y}\n")

    # **** swap variables in-line ****
    temp = x
    x = y
    y = temp
    print(f"[1] x: {x} y: {y}\n")

    # **** swap variables (for free with Python) ****
    y, x = x, y
    print(f"[2] x: {x} y: {y}\n")

    # **** swap variables (overkill using a method) ****
    x, y = swap(x, y)
    print(f"[3] x: {x} y: {y}\n")

# **** call main method ****
main()

In many real world situations we typically encounter the need to swap two values. We start this example defining a method to do so. Note that the return statement returns two values. Not all programming languages allow this. In Java we can return a data structure or object with multiple values. In C we need to pass the address of an object or data structure so the values can be in effect from the caller point of view.

Our main method defines two variables. We display them. We then swap them three times displaying the results. The first approach is how we would do in other programming languages i.e., C, C++, C# and Java. The second comes for free in Python. The third approach also works but it seems to be overkill.

S C:\Users\johnc\workspace0\CS50Python> python swap.py
[0] x: 1 y: 2

[1] x: 2 y: 1

[2] x: 1 y: 2

[3] x: 2 y: 1

PS C:\Users\johnc\workspace0\CS50Python>

The output seems to match our expectations.

# **** main method ****
def main():

    # **** ****
    s = input("input: ")
    print(f"s ==>{s}<==") # **** convert string to uppercase one character at a time **** print("outout ==>", end="")
    for c in s:
        print(c.upper(), end="")
    print("<==") # **** convert string to uppercase build in method **** s = s.upper() print(f"output ==>{s}<==")

# **** run main method ****
main()

In this example we prompt the user for a string. We traverse the string converting one character at a time. In the second approach we use a built in method to achieve the same result. The message here is to do some research when you need to get something accomplished. In most cases the answer is in your IDE. On other cases you might need to Google it.

PS C:\Users\johnc\workspace0\CS50Python> python uppercase.py
input: hello world!!!
s ==>hello world!!!<== outout ==>HELLO WORLD!!!<== output ==>HELLO WORLD!!!<== PS C:\Users\johnc\workspace0\CS50Python>

As expected, it seems both approaches yield the same result.

# **** ****
import speech_recognition as sr

# **** text response method ****
def textResponse(words):
    if "hello" in words:
        print("Hello to you too!")
    elif "how are you" in words:
        print("I am well, thanks!")
    elif "goodbye" in words:
        print("Goodbye to you too!")
    else:
        print("Huh?")

# **** main method ****
def main():

    # **** ****
    r = sr.Recognizer()
    with sr.Microphone() as source:
        print("say something: ")
        audio = r.listen(source)
        
    # **** ****
    print("Google Speech Recognition thinks you said: ")
    print(r.recognize_google(audio))

# **** call main method ****
main()

# # **** prompt for some words ****
# words = input("say something: ").lower()
# print(f"words: {words}\n")

# # **** call textResponse method ****
# textResponse(words)

We start by importing the speech_recognition library. Note that we can abbreviate the name.

We define the textReponse method that will look for specific key words in the text to generate a response.

In the main method we prompt the user to say something and as in a previous example, we use the microphone to collect what the user said. We then display what Google recognized. Note that I left the code with some text commented out. It is important to experiment in order to achieve the best results for what you are attempting to do.

PS C:\Users\johnc\workspace0\CS50Python> python voice.py    
say something:
Google Speech Recognition thinks you said:
hello world
PS C:\Users\johnc\workspace0\CS50Python> python voice.py
say something:
Google Speech Recognition thinks you said:
John what are you doing
PS C:\Users\johnc\workspace0\CS50Python> python voice.py
say something:
Google Speech Recognition thinks you said:
experimenting with python on Visual Studio code
PS C:\Users\johnc\workspace0\CS50Python>

If you uncomment the bottom section of the code, the results as illustrated seem to work well.

# **** ****
import speech_recognition as sr

# **** speech response method ****
def speechResponse(words):
    if "hello" in words:
        print("Hello to you too!")
    elif "how are you" in words:
        print("I am well, thanks!")
    elif "goodbye" in words:
        print("Goodbye to you too!")
    elif "good morning" in words:
        print("Good morning!")

    elif "good afternoon" in words:
        print("Good afternoon!")
    elif "good evening" in words:
        print("Good evening!")
    elif "goodnight" in words:
        print("Hope you sleep well tonight!")
    else:
        print("Huh?")

# **** main method ****
def main():

    # **** obtain audio from microphone ****
    r = sr.Recognizer()
    with sr.Microphone() as source:
        print("say something (use microphone): ")
        audio = r.listen(source)
        
    # **** recognize speech using Google Speech Recognition ****
    words = r.recognize_google(audio)
    print(f"words ==>{words}<==\n")

    # **** respond to speech ****
    speechResponse(words)

# **** call main method ****
main()

In this example we will get closer to a simpler approach to achieve our results in a cleaner mode.

We define a speechResponse method. It gets the words the user uttered and search for some keywords. The best match is used as a response.

The main method takes care of initializing the speech recognition library, prompt the user, get the response from the microphone and finally display a response. We could always split the code in more methods but remember to keep your code simple and short.

PS C:\Users\johnc\workspace0\CS50Python> python voice2.py
C:\Users\johnc\AppData\Local\Programs\Python\Python37\python.exe: can't open file 'voice2.py': [Errno 2] No such file or directory
PS C:\Users\johnc\workspace0\CS50Python> python voices2.py
say something (use microphone):
words ==>good morning Google<== Good morning! PS C:\Users\johnc\workspace0\CS50Python> python voices2.py
say something (use microphone):
words ==>how are you<== I am well, thanks! PS C:\Users\johnc\workspace0\CS50Python> python voices2.py
say something (use microphone):
words ==>bye-bye Google<== Huh? PS C:\Users\johnc\workspace0\CS50Python> python voices2.py
say something (use microphone):
words ==>goodbye Google<== Goodbye to you too! PS C:\Users\johnc\workspace0\CS50Python>

The results seem to be reasonable. We could continue to work on this code perhaps by requesting the name of the user and then adding it to future questions. That sounds like a nice exercise.

# **** ****
import re
import speech_recognition as sr

# **** respond to speech method ****
def speechResponse(words):
    
    # **** ****
    matches = re.search("my name is (.*)", words)
    #print(f"type(matches): {type(matches)}")

    # **** build proper response ****
    if matches:
        print(f"matches: {matches}\n")
        print(f"Hey, {matches[1].title()}!!!")
    else:
        print("Hey you.")

# **** main method ****
def main():

    # **** obtain audio from microphone ****
    r = sr.Recognizer()
    with sr.Microphone() as source:
        print("say: my name is ... (use microphone): ")
        audio = r.listen(source)
        
    # **** recognize speech using Google Speech Recognition ****
    words = r.recognize_google(audio)
    print(f"words ==>{words}<==\n")

    # **** respond to speech ****
    speechResponse(words)

# **** call main method ****
main()

This example is similar to the previous one. The main difference is that we will use regular expressions to extract the name of the user and then construct a better tailored response.

PS C:\Users\johnc\workspace0\CS50Python> python voices3.py   
say: my name is ... (use microphone):
words ==>my name is John<==

matches: <re.Match object; span=(0, 15), match='my name is John'>

Hey, John!!!
PS C:\Users\johnc\workspace0\CS50Python> python voices3.py
say: my name is ... (use microphone):
words ==>my name is James<==

matches: <re.Match object; span=(0, 16), match='my name is James'>

Hey, James!!!
PS C:\Users\johnc\workspace0\CS50Python> python voices3.py
say: my name is ... (use microphone):
words ==>my name is Bond James Bond<==

matches: <re.Match object; span=(0, 26), match='my name is Bond James Bond'>

Hey, Bond James Bond!!!
PS C:\Users\johnc\workspace0\CS50Python>

As long as the response matches the expected format, the program responds with tailored ones.

At this point we will create a GitHub repository. Note that the name has to be different than the name of the folder we used to hold our code and data. We do not want to lose what we have done.

# **** we want to put our new code in our workspace ****
C:\Users\johnc>dir
05/05/2020  01:51 PM    <DIR>          .
05/05/2020  01:51 PM    <DIR>          ..
09/22/2019  08:00 AM    <DIR>          .eclipse
03/15/2020  08:38 AM                59 .gitconfig
04/23/2020  11:11 AM    <DIR>          .p2
05/07/2020  08:11 AM         1,005,502 .pipwin
04/21/2020  08:07 AM    <DIR>          .pylint.d
09/22/2019  08:00 AM    <DIR>          .tooling
03/10/2020  03:53 PM    <DIR>          .vscode
03/10/2020  04:43 PM    <DIR>          3D Objects
03/10/2020  04:43 PM    <DIR>          Contacts
04/08/2020  07:59 AM    <DIR>          ContainsCloseNums
02/17/2020  03:52 PM    <DIR>          Documents
05/07/2020  12:28 PM    <DIR>          Downloads
09/22/2019  07:57 AM    <DIR>          eclipse
09/22/2019  07:59 AM    <DIR>          eclipse-workspace_0
03/10/2020  04:43 PM    <DIR>          Favorites
03/10/2020  04:44 PM    <DIR>          Links
03/10/2020  04:43 PM    <DIR>          Music
09/12/2019  04:36 PM    <DIR>          NCH Software Suite
05/08/2020  07:19 AM    <DIR>          OneDrive
05/04/2020  03:42 PM    <DIR>          pipwin
03/10/2020  04:43 PM    <DIR>          Saved Games
03/10/2020  04:43 PM    <DIR>          Searches
03/10/2020  04:43 PM    <DIR>          Videos
05/05/2020  01:30 PM    <DIR>          vimfiles
05/07/2020  02:40 PM    <DIR>          workspace0
05/05/2020  01:51 PM             3,281 _viminfo

# **** ****
C:\Users\johnc>cd workspace0

# **** looks like we alreaady have created a folder with the same name ****
05/07/2020  02:40 PM    <DIR>          .
05/07/2020  02:40 PM    <DIR>          ..
04/01/2020  08:57 AM    <DIR>          BST-Search
04/27/2020  08:46 AM    <DIR>          ClassesInPython
04/10/2020  11:34 AM    <DIR>          ComposeRanges
04/08/2020  08:04 AM    <DIR>          ContainsCloseNums
05/08/2020  09:32 AM    <DIR>          CS50Python
05/07/2020  02:44 PM    <DIR>          DownToZeroII
04/05/2020  08:32 AM    <DIR>          GraphBFS
04/21/2020  07:46 AM    <DIR>          Knights
04/24/2020  08:33 AM    <DIR>          Minesweeper
04/17/2020  03:41 PM    <DIR>          MissingNumber
03/29/2020  08:30 AM    <DIR>          ORCost
04/23/2020  11:13 AM    <DIR>          Python-Tutorial-CS50
04/22/2020  04:37 PM    <DIR>          PythonTutorial
04/19/2020  07:46 AM    <DIR>          RobotInAGrid
03/10/2020  04:24 PM    <DIR>          SortOnFrequency
04/29/2020  02:47 PM    <DIR>          UsingWithPython
04/28/2020  02:52 PM    <DIR>          WorkingWithFiles

# **** clone the GitHub repository ****
C:\Users\johnc\workspace0>git clone https://github.com/JohnCanessa/CS50Python.git
Cloning into 'CS50Python'...
remote: Enumerating objects: 3, done.
remote: Counting objects: 100% (3/3), done.
remote: Compressing objects: 100% (2/2), done.
remote: Total 3 (delta 0), reused 0 (delta 0), pack-reused 0
Unpacking objects: 100% (3/3), 862 bytes | 7.00 KiB/s, done.

# **** ****
C:\Users\johnc\workspace0>cd CS50Python

# **** ****
C:\Users\johnc\workspace0\CS50Python>dir
05/08/2020  11:47 AM    <DIR>          .
05/08/2020  11:47 AM    <DIR>          ..
05/08/2020  11:48 AM                32 .gitignore
05/08/2020  11:36 AM    <DIR>          .vscode
05/08/2020  07:34 AM               701 agree.py
05/08/2020  07:38 AM               351 argv.py
05/08/2020  07:38 AM               236 blur.py
04/30/2020  11:50 AM             7,518 bridge.jpg
05/07/2020  12:30 PM           530,495 carmen.jpg
05/08/2020  07:41 AM               426 compare.py
04/30/2020  04:15 PM               233 conditions.py
05/08/2020  07:45 AM               539 cough.py
05/08/2020  07:48 AM             1,205 detect.py
05/08/2020  08:04 AM            85,878 dict.txt
05/08/2020  08:17 AM             2,145 dictionary.py
05/08/2020  08:46 AM               778 exit.py
05/08/2020  08:52 AM             1,176 hello.py
05/08/2020  08:53 AM               152 int.py
05/07/2020  12:21 PM         1,650,243 john.jpg
05/07/2020  07:48 AM         2,365,218 malan.jpg
05/01/2020  10:04 AM               412 mario.py
05/08/2020  09:00 AM             1,054 names.py
05/08/2020  07:39 AM             6,684 out.jpg
05/08/2020  09:02 AM               200 overflow.py
05/08/2020  09:09 AM               232 phonebook.csv
05/08/2020  09:06 AM               953 phonebook.py
05/08/2020  09:08 AM               643 phonebook1.py
05/08/2020  09:11 AM               576 positive.py
05/08/2020  11:34 AM               423 README.md
05/08/2020  09:29 AM             2,063 recognize.py
05/07/2020  11:57 AM            82,484 rome_italy.jpg
05/08/2020  10:22 AM               693 scores.py
05/08/2020  10:54 AM               873 speech.py
05/08/2020  10:56 AM               144 string0.py
05/08/2020  10:58 AM               486 string1.py
05/08/2020  11:01 AM               598 swap.py
05/08/2020  11:03 AM               436 uppercase.py
05/08/2020  11:05 AM               877 voice.py
05/08/2020  11:07 AM             1,128 voices2.py
05/08/2020  11:24 AM               929 voices3.py
05/07/2020  07:48 AM        13,345,640 yale.jpg
05/05/2020  02:27 PM    <DIR>          __pycache__

# **** generated and types the .gitignore file ****
C:\Users\johnc\workspace0\CS50Python>type .gitignore
.vscode
__pycache__
.gitignore

# **** as expected some files are being ignored ****
C:\Users\johnc\workspace0\CS50Python>git status
On branch master
Your branch is up to date with 'origin/master'.

Untracked files:
  (use "git add <file>..." to include in what will be committed)
        agree.py
        argv.py
        blur.py
        bridge.jpg
        carmen.jpg
        compare.py
        conditions.py
        cough.py
        detect.py
        dict.txt
        dictionary.py
        exit.py
        hello.py
        int.py
        john.jpg
        malan.jpg
        mario.py
        names.py
        out.jpg
        overflow.py
        phonebook.csv
        phonebook.py
        phonebook1.py
        positive.py
        recognize.py
        rome_italy.jpg
        scores.py
        speech.py
        string0.py
        string1.py
        swap.py
        uppercase.py
        voice.py
        voices2.py
        voices3.py
        yale.jpg

nothing added to commit but untracked files present (use "git add" to track)

# **** add the files to be commited ****
C:\Users\johnc\workspace0\CS50Python>git add *

# **** see what we will commit ****
C:\Users\johnc\workspace0\CS50Python>git status
On branch master
Your branch is up to date with 'origin/master'.

Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
        new file:   agree.py
        new file:   argv.py
        new file:   blur.py
        new file:   bridge.jpg
        new file:   carmen.jpg
        new file:   compare.py
        new file:   conditions.py
        new file:   cough.py
        new file:   detect.py
        new file:   dict.txt
        new file:   dictionary.py
        new file:   exit.py
        new file:   hello.py
        new file:   int.py
        new file:   john.jpg
        new file:   malan.jpg
        new file:   mario.py
        new file:   names.py
        new file:   out.jpg
        new file:   overflow.py
        new file:   phonebook.csv
        new file:   phonebook.py
        new file:   phonebook1.py
        new file:   positive.py
        new file:   recognize.py
        new file:   rome_italy.jpg
        new file:   scores.py
        new file:   speech.py
        new file:   string0.py
        new file:   string1.py
        new file:   swap.py
        new file:   uppercase.py
        new file:   voice.py
        new file:   voices2.py
        new file:   voices3.py
        new file:   yale.jpg

# **** commit the new files ****
C:\Users\johnc\workspace0\CS50Python>git commit -m "set of Python and JPEG files"
[master eeef32d] set of Python and JPEG files
 36 files changed, 10850 insertions(+)
 create mode 100644 agree.py
 create mode 100644 argv.py
 create mode 100644 blur.py
 create mode 100644 bridge.jpg
 create mode 100644 carmen.jpg
 create mode 100644 compare.py
 create mode 100644 conditions.py
 create mode 100644 cough.py
 create mode 100644 detect.py
 create mode 100644 dict.txt
 create mode 100644 dictionary.py
 create mode 100644 exit.py
 create mode 100644 hello.py
 create mode 100644 int.py
 create mode 100644 john.jpg
 create mode 100644 malan.jpg
 create mode 100644 mario.py
 create mode 100644 names.py
 create mode 100644 out.jpg
 create mode 100644 overflow.py
 create mode 100644 phonebook.csv
 create mode 100644 phonebook.py
 create mode 100644 phonebook1.py
 create mode 100644 positive.py
 create mode 100644 recognize.py
 create mode 100644 rome_italy.jpg
 create mode 100644 scores.py
 create mode 100644 speech.py
 create mode 100644 string0.py
 create mode 100644 string1.py
 create mode 100644 swap.py
 create mode 100644 uppercase.py
 create mode 100644 voice.py
 create mode 100644 voices2.py
 create mode 100644 voices3.py
 create mode 100644 yale.jpg

# **** ****
C:\Users\johnc\workspace0\CS50Python>git status
On branch master
Your branch is ahead of 'origin/master' by 1 commit.
  (use "git push" to publish your local commits)

nothing to commit, working tree clean

# **** push changes to GitHub ****
C:\Users\johnc\workspace0\CS50Python>git push origin master
Enumerating objects: 39, done.
Counting objects: 100% (39/39), done.
Delta compression using up to 12 threads
Compressing objects: 100% (38/38), done.
Writing objects: 100% (38/38), 16.97 MiB | 1.38 MiB/s, done.
Total 38 (delta 2), reused 0 (delta 0)
remote: Resolving deltas: 100% (2/2), done.
To https://github.com/JohnCanessa/CS50Python.git
   435d7f3..eeef32d  master -> master

# **** ****
C:\Users\johnc\workspace0\CS50Python>git status
On branch master
Your branch is up to date with 'origin/master'.

nothing to commit, working tree clean

# **** ****
C:\Users\johnc\workspace0\CS50Python>git log
commit eeef32dd4fa060ad58d8af443c024d2ca7731a91 (HEAD -> master, origin/master, origin/HEAD)
Author: JohnCanessa <john.canessa@gmail.com>
Date:   Fri May 8 11:57:39 2020 -0500

    set of Python and JPEG files

commit 435d7f3f54112a5114e37a43637d12f07ee7f871
Author: John Canessa <8019504+JohnCanessa@users.noreply.github.com>
Date:   Fri May 8 11:33:32 2020 -0500

    Create README.md

Note that we create a .gitignore file to avoid uploading some of the files that are only of interest to our development process. We commit the files. When done we push them to our GitHub repository.

The entire code for this project can be found in my GitHub repository.

If you have comments or questions regarding this, or any other post in this blog, or if you would like for me to serve of assistance with any phase in the SDLC (Software Development Life Cycle) of a project associated with a product or service, please do not hesitate and leave me a note below. If you prefer, send me a private message using the following address:  john.canessa@gmail.com. I will reply as soon as possible.

Keep on reading and experimenting. It is the best way to learn, refresh your knowledge and enhance your developer toolset!

One last thing, many thanks to all 941 subscribers to my blog!!!

Keep safe during the COVID-19 pandemic.

John

Twitter:  @john_canessa

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.