Viren Bhagat

My Notes: Python (CS50)

5/5/2020

Today will introduce a new language, Python.

Python is an interpreted, high-level, general-purpose programming language. It can be used for many different things, ranging from data science to web development.

As opposed to working with C earlier, we do not have to worry about compiling our code.

To print "hello world" in C, our program looked something like this:

//hello.c
#include <stdio.h>

int main(void)
{
    printf("hello world\n");
}

Then we'd have to compile the code and run the output file.

clang -o hello hello.c -lcs50
./hello

With Python, our file is a bit shorter and we do not have to compile the code, it can just be ran in the terminal window.

//hello.py

print("hello world")

And it is ran with the command, python hello.py.

To set variables, you do not have to mention the data type. For example, in C it would be int counter = 0;, now in Python, we can just declare counter = 0. Increment and decrementing is the same but the semi-colon isn't required in Python.

For if statements, Python's syntax is a little more condensed:

if (x > y)
{
    printf("x is greater than y\n");
}

Python looks like:

if x > y:
    print("x is greater than y")

No parentheses, no semicolon, no curly brackets. The indentation is necessary as Python is sensitive to white spacing.

For a lot of converting to Python from C, there will be less curly braces and semicolons, more colons and whitespacing though. A for loop in Python can look like the below:

for i in [0, 1, 2]:
    print("cough")

If it is a bigger size to loop through, we can use range(25) instead of [0,1,...,25].

In Python, we don't have to worry about creating lower level data structures as we had to create them in C (linked lists, tries, etc.). Python has a lot of data structures built in so we don't have to think too low into the language.

We have range, list, tuple, dict, set just to mention a few data structures that Python gives us.

  • range - sequence of numbers
  • list - sequence of mutable values
  • tuple - sequence of immutable values (cannot change the values)
  • dict - collection of key/value pairs (hash tables)
  • set - collection of unique values

To implement a hash table in Python, a bit more simple than in C:

words = set()

def check(word):
    if word.lower() in words:
        return True
    else: 
        return False

def load(dictionary):
    file = open(dictionary, "r") # r for read mode
    for line in file:
        words.add(line.rstrip("\n"))
    file.close()
    return True

def size():
    return len(words)

def unload():
    return True

Running it in Python versus C, Python outputted a bit slower. But implementing in Python is a lot quicker than writing the program in C. This is where you have to think of the tradeoffs. You have to think about the time to develop the program and the time it takes to run the program. If the program was being used by many users, you would want a quickly executing program. Therefore, it could be better to write it in C, spend more time developing it.


Getting and Printing Input

Let's now compare some more of the problems from earlier weeks but implement the programs using Python instead of C.

Here was a program from week 1, written in C, to obtain the user's name.

#include <cs50.h>
#include <stdio.h>

int main(void)
{
    string s = get_string("What's your name?");
    printf("hello, %s\n", s);
}

Seven or eight lines of code, depending on how you count. In Python, we can spin up something like this -

from cs50 import get_string 

s = get_string("What's your name?\n")
print("hello, " + s)

We import the function from cs50 library, set a variable to get the user's name, then print it out. We can also use alternatives to print. print("hello,", s) or also print(f"hello {s}")

Here was a program we had made in C to get a user's age in a number of days.

#include <cs50.h>
#include <stdio.h>

int main(void)
{
    int age = get_int("What's your age?\n");
    printf("You are at least %i days old.\n", age * 365);
}

We just take the user's input (an integer), multiply the age by 365 days, and print it out.

Here is the same program in Python.

from cs50 import get_int

age = get_int("What's your age?\n")
print(f"You are at least {age * 365} days old.")

Comparing values with if statements

In C,

#include <cs50.h>
#include <stdio.h>

int main(void)
{
    // Prompt user for x
    int x = get_int("x: ");
    
    // Prompt user for y
    int y = get_int("y: ");
    
    // Compare
    if (x < y)
    {
        printf("x is less than y\n");
    }
    else if (x > y)
    {
        printf("x is greater than y\n");
    }
    else
    {
        printf("x is equal to y\n");
    }
}

Here is how to make the same in Python,

from cs50 import get_int

x = get_int("x: ")
y = get_int("y: ")

if x < y:
    print("x is less than y")
elif x > y:
    print("x is greater than y")
else:
    print("x is equal to y")

Note, again, there are less curly braces and you have to focus more on indenting correctly and colons instead of parentheses.


Creating Reusable Code (w. Functions)

for i in range(3):
    cough()
    
def cough():
    print("cough")

In C, we needed the main() function. Let's see how the above code would work. This is the error message we receive in the terminal.

Traceback (most recent call last):
  File "cough.py", line 2, in <module>
    cough()
NameError: name 'cough' is not defined

Our function, cough() is undefined. The function was defined after it was called, as our error mentions. We had an issue like this in C, but we used prototypes to deal with it. It is better to put the main code up top, then the helper code after that. We can resort back to creating a main() function. We can re-write the code to work as below -

def main():
    for i in range(3):
        cough()
    
def cough():
    print("cough")

main()  

We call our main() at the end, so we get out desired and expected output, cough three times.

Lets try to make the code more dynamic now. Let us be able to input the amount of times we cough.

def main(x):
    cough(x)
    
def cough(n):
    for i in range(n):
        print("cough")

main(3) 

Some Looping

There is no do..while loop in Python but there are alternatives to achieve the same output.

#include <cs50.h>
#include <stdio.h>

int get_positive_int(void);

int main(void)
{
    int i = get_positive_int();
    printf("%i\n", i);
}

// Prompt user for positive integer
int get_positive_int(void)
{
    int n;
    do
    {
        n = get_int("Positive integer: ");
    }
    while (n < 1);
    return n;
}

Python -

from cs50 import get_int

def main():
    i = get_positive_int()
    print(i)

def get_positive_int():
    while True:
        n = get_int("Positive Integer: ")
        if n > 0:
            break
    return n        

main()          

Working without the cs50 library in Python

We will see we don't really need to utilize the cs50 library to import, get_int(), get_string(), etc.

We can use input(), built into Python. The type is always a string.

age = input("What's your age?\n")

The value will be saved an a string, not an an integer. It can be converted by wrapping the input in an int()

age = int(input("What's your age?\n"))

Overflows in Python

from time import sleep

i = 1
while True:
    print(i)
    sleep(1)
    i *= 2

*** The sleep() function suspends (waits) execution of the current thread for a given number of seconds. It is from a library called time.

The above code will print numbers above 4 billion and does not stop. Integers have no upper bounds, there is no fixed limit like there was in C.


Arrays (known as Lists in Python)

Here we will make an array (rather a list), with grades, and get the average.

scores = []
scores.append(72)
scores.append(73)
scores.append(33)

print(f"Average: {sum(scores) / len(scores)}")

Python has some built in methods, we can do all the math in the print statement. append() is a method on the list type.

The below code works exactly the same.

scores = [72, 73, 33]
print(f"Average: {sum(scores) / len(scores)}")

Lists can grow and shrink. We don't have to think about allocating memory like we did in C.


Iteration over Strings

We have had to use a for loop to access each index of the string and print it out.

from cs50 import get_string

s = get_string("Input: ")
print("Output: ", end="")
for i in range(len(s)):
    print(s[i], end="")
print()

Above can be simplified a little bit:

from cs50 import get_string

s = get_string("Input: ")
print("Output: ", end="")
for c in s:
    print(c, end="")
print()

To convert a string to uppercase a lot more simple as well:

from cs50 import get_string

s = get_string("Before: ")
print("After: ", end="")
print(s.upper())

Linear Searching

from sys import exit

names = ["EMMA", "RODRIGO, "BRIAN", "DAVID"]

if "EMMA" in names:
    print("Found")
    exit(0)
print("Not Found")
exit(1) 

Again, we don't have to use a for loop like in C.


Phonebook Example

from sys import exit

people = {
    "EMMA": "617-555-0100",
    "RODRIGO": "617-555-0101",
    "BRIAN": "617-555-0102",
    "DAVID": "617-555-0103"
}

def find(name):
    if name in people:
        print(f"{name}'s number: {people[name]}")
        exit(0)
    print("Not found")      

find("DAVID")

Let us use a hash table (or dictionary) instead of just a list (or array). Dictionaries are based on key-value pairs. The names are our keys, the phone numbers being the values. A dictionary is also known as an associative array.


Comparing Strings

We had trouble comparing strings in C because they were pointers to chars. As they were stored in different memory places, we faced issues and had to use strcmp() // string compare.

Let's see how we would compare strings in Python. Technically, the two variables have different memory locations as well but Python takes a literal comparison of the two strings.

from cs50 import get_string

s = get_string("s: ")
t = get_string("t: ")

if s == t:
    print("Same")
else:
    print("Not same")   

What about swapping values?

It was a task as we had to refer to pointers in C.

#include <stdio.h>

void swap(int *a, int *b); // Prototype of swap function

int main(void)
{
    int x = 1;
    int y = 2;
    
    printf("x is %i, y is %i\n", x, y);
    swap(&x, &y);
    printf("x is %i, y is %i\n", x, y);
}

void swap(int *a, int *b)
{
    int tmp = *a;
    *a = *b;
    *b = tmp;
}

To swap in Python,

x = 1
y = 2

print(f"x is {x}, y is {y}")
x, y = y, x
print(f"x is {x}, y is {y}")

Phonebook & Saving to a CSV

From a previous week, we had created a phonebook.csv and were saving names and numbers to the .csv file. It can also be done in Python.

We will use a csv package library to help us create this program.

import csv
from cs50 import get_string

file = open("phonebook.csv", "a") # "a" for appending

name = get_string("Name: ")
number = get_string("Number: ")

writer = csv.writer(file)
writer.writerow((name, number))

file.close()

Regular Expressions

Regular expressions, or regex, are a way to detect patterns of text.

Regex 101

Here is an earlier program where using a regular expression would be helpful instead of using the lower() method on the string input.

from cs50 import get_string

s = get_string("Do you agree?\n")

if s.lower() in ["y", "yes"]
    print("Agreed")
elif s.lower() in ["n", "no"]
    print("No") 

import re is a regular expression library for Python.

import re
from cs50 import get_string

s = get_string("Do you agree?\n")

if re.search("^y(es)?$", s, re.IGNORECASE):
    print("Agreed")
elif re.search("^n(o)?$", s):
    print("No") 

The regular expression here is searching the input, for a 'y' and maybe something after that or a 'n' and something after that (i.e. "no"). The ^ character is to search from the beginning of the string and $ is to the end of the string.


Resources, Sources, & Useful Links

Lecture (on YouTube)

CS50 IDE

CS50 Course on edX

cs50, python