Python Fundamentals 2#

Review and Outline#

Great Work! We have made it this far…we know some basic calculations, data types and structures (lists, tuples, strings, dictionaries), we also know how to get help ? and read Error: messages. Finally, we should be getting comfortable with the notebook and markdown.

Where are we going? In this notebooke we will cover some key operations: Comparisons, if else conditional operations, for loops. In the end, we will learn the core concept of object in object oriented programming and how it is used in python to help us better understand the language.

This notebook largely follows the discussion in the Book. Note, in the book there are many more excercises to try. Pleast try them at home.

Python Tools#

Boolean variables, comparisons, conditionals (if, else), slicing, loops (for), tab completion, function definitions and objects.

Buzzwords. Code block, data structures, list comprehension, PEP8.


Booleans#

Basic idea, make a comparison and the result is a true or false value. We call these bools…

test = 1 < 0 # This is a comparsition, value 1 versus zero....
print(test) # What does it return a True or False value...
print(type(test)) 
False
<class 'bool'>

KEY Note the type, it’s a bool or short for Boolean.

Here are some more operations…bools can be combined with integers and floats…

print(2*test)

# Now what if we had 1 < 0 above, what would the command return... note that it will
# give a zero... so what is going on here is implicitly with a True is the value 1
# and associated with the value False is a zero (note how in the background there is
# probably a dictionary doing this....)

test1 = 0.666666666666666666 # This is interesing, when are they equal...
test2 = 2/3
print(test1 == test2)
0
True

Some more operations… == is equal, >= greater than or equals, <= less than or equals, != not equals. Keep these in mind. There are also other ways to take the oppisite value by using the not built-in

test = not 1 > 0 # this is not whatever 1 > 0 is, so not True which is FALSE
print(test)
False

Then notice what happens when we print a statement…

x = 2*3
y = 2**3
print('x greater than y is', x > y)
x greater than y is False

Exercise. What is 2 >= 1? 2 >= 2? not 2 >= 1? If you’re not sure, try them in the IPython console and see what you get.

Exercise. What is

print(2 + 2 == 4) 

print(1 + 3 != 4) 

Explain what is going on here….

Exercise What is

print("sarah" == 'Sarah')

Exercise. What do these comparisons do? Are they true or false? Why?

print(type('Sarah') == str) # IS it a string? YES!!! 
print(type('Sarah') == int) # IS it an integer??? NO!
print(len('Sarah') >= 3) # Is the length longer than three? YES!
True
False
True

Comparisons in String

name1 = 'Chase'
name2 = 'Spencer'
check =  name1 > name2
print("Is Chase > Spencer ",check) #hmmmm....
Is Chase > Spencer  False

https://stackoverflow.com/questions/4806911/string-comparison-technique-used-by-python

Here is the quick run down, this does this thing in lexicographic ordering… this means: First the first two items are compared, and if they differ this determines the outcome of the comparison; if they are equal, the next two items are compared, and so on, until either sequence is exhausted. What determines the order…in this case note that “S” comes later in the alphabet than “C” thus is has a larger “value”, thus “Chase > Spencer” is false.

When comparing uppercase vs. lower case, uppercase come before lower case…The stuff like *& come before. How do I know exactly what is going on… here is a link to the unicode point ordering

https://en.wikipedia.org/wiki/List_of_Unicode_characters

And scroll down to the Latin Script /Basic Latin table there. There there is a number for each possible character. To see the number just type ord("z") and note how this should give back the value 122 and then look in the table it should have the value 122. In the comparison above, what it is doing is taking the number in this table for the given character and then comparing it to the number for the other character.

"z" > "a"
True
ord("!")
33

Conditional (If/Else)#

Now that we know how to tell whether a comparison is true or false, we can build that into our code. “Conditional” statements allow us to do different things depending on the result of a comparison or Boolean variable, which we refer to as a condition. The logic looks like this:

  • if a condition is true, then do something.

  • if a conditions is false, do something else (or do nothing).

if 1 > 0: # this statment checks the value, then IF TRUE it advances to the next line
    print("1 is greater than 0") # here where it prints the value
    print("test")
1 is greater than 0
test

Key issue, an if statement must always be followed by : and then the next line or lines associated with the statement must be indicated by 4 spaces. ONLY 4 spaces, Jupyter will do this automatically….there is also some kind of debate about spaces or tabs…here is some interesting info if you need to choose:

https://stackoverflow.blog/2017/06/15/developers-use-spaces-make-money-use-tabs/

x = 5               # we can change this later and see what happens

if x > 6:
    print('x =', x)

print('Done!')
Done!
x = 7

condition = x > 6

if condition:
    print('if branch')             # do if true
    print(condition)
else:
    print('else branch')           # do if false
    print(condition)
if branch
True

Exercise. Take the names name1 and name2, both of them strings. Write a program using if and else that prints the name that comes first in alphabetical order. Test your program with name1 = ‘Dave’ and name2 = ‘Glenn’.

name1 = 'Dave'
name2 = 'Glenn'

Exercise Make it insensitive to capitalization…


Slicing#

This is important stuff to be comfortable with. When we start to work with Pandas (the data package), slicing will be a key skill to “slice” the data in the way that we want. For now we will work with strings and lists.

a = "some"
print([a[0], a[1], a[2]])

# Note how it is treating the string just like a tuple (remember python starts indexing from 0)
# so we are calling each individual character...
['s', 'o', 'm']
a[1] = "*"  # can we re-assgin? # no...string is like a tuple where the object is immutable.
print(a)
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
Cell In[14], line 1
----> 1 a[1] = "*"  # can we re-assgin? # no...string is like a tuple where the object is immutable.
      2 print(a)

TypeError: 'str' object does not support item assignment

One of the interesting things about this is that there are both a forward counter and a backward counter. Here is an example:

print(a[-3]) # this should give an o, so 0 is s, -1 is e, -2, is m...
#print(a[-400]) # But it will not do this infinitly, it will do this untill it returns
# back to s or -4,  

Exercise Take the string firstname = ‘Monty’ and write below it the forward and backward counting conventions. What integer would you put in square brackets to extract the third letter (n) under each system?

Exercise. Find the last letter of the string lastname = ‘Python’. Find the second to last letter using both the forward and backward counting conventions.

Exercise. Take the list numberlist = [1, 5, -3]. Use slicing to set a variable first equal to the first item. Set another variable last equal to the last item. Set a third variable named middle equal to the middle item.

Now how do we pull groups of objects out of a data structure. We use the : operator. What this does is when we have say [0:2] this will pull out the first element AND everything after it NOT including the object in the second position. That is the value after the colon is not included. LEts see this…

c = 'something'

print('c[1] is', c[1]) # We know this...
print('c[1:2] is', c[1:2]) # This says take between 1 and 2 NOT including 2 (so same as above)
print('c[1:3] is', c[1:3]) # This says take between 1 and 3 NOT including 3
print('c[1:] is', c[1:]) # This says give from postion 1 onward so omething...if -1?
print('c[1:-1] is', c[1:-1]) # This works, again, from postion 1 and -1 NOT including -1, so oemthin

Exercise. Set lastname = ‘Python’. Extract the string ‘thon’.

Exercise. Set numlist = [1, 7, 4, 3]. Extract the middle two items and assign them to the variable middle.

Exercise.

  • Extract all but the first item and assign them to the variable allbutfirst.

  • Extract all but the last item and assign them to the variable allbutlast.

allbutfirst = ''
allbutlast = ''

for Loop#

As with the conditional operation, this is a key skill. In particular, it allows for us to scale up the number of operations without having to constantly write code to perform each one.

The book has some examples, but let me suggest one that I see all the time…suppose you have bunch of datasets. How to you read them in. Use a for loop. So you create a list of the names of the data sets, then you work through the list and read each one it. What the for loop allowed you to do is for a small change in your code you have scaled your operation by however much.

namelist = ['Chase', 'Dave', 'Sarah', 'Spencer']    # creates the list "namelist"
# below, the word "item" is arbitrary. End the line with a colon.

for item in namelist:    # goes through the items in the list one at a time
    print(item)    # indent this line exactly 4 spaces
# if there is code after this, we'd typically leave a blank line in-between

One thing to notice is the item which is a place holder. The specific name item has no attachment to anything, all it says is that as it works through each object in the list, its temporary name will be item. Here, try to change item to bloob and see what happens.

Here is a numerical calculation…this is common in scientific computing…

numlist = [4, -2, 5]
total = 0

for num in numlist:
    total = total + num

print(total)

Now here is a string.

word   = 'anything'
for letter in word:
    print(letter)

Note how general this is. The key issue is that as long as the for loop is over an “itteratable” object, then this this will work. Ask your self, what itterable objects do we know.

Now this example below combines the for loop and a conditional

vowels = 'aeiouy'
word   = 'anything'

for letter in word:
    
    if letter in vowels:
        
        print(letter)

Exercise. Take the list stuff = ['cat', 3.7, 5, 'dog'].

  • Write a program that prints the elements of stuff.

  • Write a program that tells us the type of each element of stuff.

  • Challenging. Write a program that goes through the elements of stuff and prints only the elements that are strings; that is, the print the elements where function type returns the value str.

Exercise. Consider the list namelist = ['Chase', 'Dave', 'Sarah', 'Spencer'].

Write a loop that goes through the list until it reaches a name than begins with the letter S. At that point it prints the names and exits the loop.

Loops over Ranges#

I think this is less important in data work. We need to know it though, so let’s work through it. The first thing to learn is the type range

range?
my_first_range = range(0,10,2)
type(my_first_range)
print(list(my_first_range)) # why do need to add a list() function in print function?
for number in range(1,5,2): # the variable "number" can be anything
    
    print(number)
for number in range(1, 11):
    square = number**2
    
    print('Number and its square:', number, square)

List Comprehension#

The basic idea is to create implicit loops on itterable objects like lists (note it need not be a list, just something we can itterate on). We refer to this as list comprehensions. It is useful in certain circumstances and shows up a lot in Python code.

To understand list list comprehension, lets first remind our selves what a loop is doing

namelist = ['Chase', 'Dave', 'Sarah', 'Spencer']

for item in namelist:
    
    print(item)

A list comprehension gives us more compact syntax for the same thing:

[print(item) for item in namelist]

Notices what this is doing:

  • First there are the square brackets, this means we are creating a NEW LIST

  • The first part within the brackes is the operation we want to perform on the old list. Here we want to print it.

  • Then after the operation on the “item” we describe the for operation, the variable, and then the itterable oject we want to grab from.

  • Essentialy what all this says is “do operation on item in the list”

Again, as with loops, the variable item is a dummy: we can use any name we wish. Replace item with your pet’s name to see for yourself.

Lets see some examples:

fruit = ['apple', 'banana', 'clementine'] # A list...

FRUIT = [item.upper() for item in fruit] 

print(FRUIT)

We can also apply conditions within list comprehensions

fruit6 = [item for item in fruit if len(item)<=6]
fruit6

Exercise. Take the list of growth rates g = [0.02, 0.07, 0.07]. Write a list comprehension that multiplies each element by 100 to turn it into a percentage.

g = [0.02, 0.07, 0.07]

Exercise. Take the mixed type list [True, "2", 3.0, 4] and create a new list of the associated types.

h = [True, "2", 3.0, 4]

Final point about this: List comprehensions and related stuff are okay to use for simple cases. However, for more complicated situations, comprehensions be very hard to read and understand. Hence, a traditional for loop would be more appropriate.


Functions#

The key idea here is that rather than repeating the same lines of code over and over again. We can create a function that performs some distinct operation. This is a good strategy for a lot of reasons

  • Efficient in terms of writing code

  • It facilitates easy to read code

  • Avoids any debuging issue that may arise when you have to modify multiple lines of code in the same exact way (just change the code in the function).

  • Finally, it will give us insight to what is behind various packages that we will be using in the future…what are they just a collection of functions!

def hello(firstname):               # define the function
    print('Hello,', firstname)
      

A couple of things:

  • Similar syntax to for loops, if statements. Here we start with def (short for definition), then we create the name of the function and then any inputs…

  • Four spaces for all operations preformed by the function. If it does not have four spaces, it is not recognized as part of the function.

One more thing. We have only have to run this code cell once. Once we do so the function is in the namespace and is good to go.

hello('Chase')   
hello([1,2,3])
ans = hello('Lenny')
print(ans)
whos

This shows us that the function is there and available.

Returning to the function above, how would I modify it to return a different message if firstname is not a string?

Now sometimes we want the function to return a value…this is how we do it.

def squareme(number):
    """
    Takes numerical input and returns its square
    """
    return number**2, number        # this is what the function sends back
squareme(2)
x, y = squareme(2)
y
def value_one():               # define the function
    return 1.0
value_one()
max?
def combine(first, last):
    """
    Takes strings 'first' and 'last' and returns new string 'last, first'
    """
    lastfirst = last + ', ' + first
    return lastfirst                    # this is what the function sends back

both = combine('Chase', 'Coleman')      # assign the "return" to both
print(both)
  • Exercise. Create and test a function nextyear that takes an integer year (say 2015) and returns the following year (2016).

  • Exercise. Create and test a function that takes a string year (say, ‘2015’) and returns a string of the next year (say, ‘2016’).

  • Exercise. Write a function that extracts the last letter from a string

  • Exercise. Use the function above and write a program so that last letter of each item in the list names = [‘Chase’, Dave’, ‘Sarah’, ‘Spencer’] is printed

  • Bonus (optional): Print the last letter only if it’s a vowel.


Objects#

This is a key feature of python…it’s an object oriented programming language. What does that mean? For us this means that every thing is really an object with associated methods and attributes. A method is like a function that already togo with the given object. Methods in python are always completed with () . Attributes are go-to-go attributes about the object that can be accessed easily. What this means is that there are simple built-in ways to get information and perform operations on objects without having to write our on functions.

Functions, methods, and attributes differ primarily in their syntax:

  • Syntax of a function: function(object)

  • Syntax of a method: object.method()

  • Syntax of a attribute: object.attribute

We used the former in the previous section and will consider the latter here.

OK…but if I have say a list, how do I know the methods and attributes associated with it…here comes TAB completion which we covered in last Notebook.

whos
numberlist.append?
numberlist.append(7)

print(numberlist)
first_name = "Chase"
first_name.lower()

Exercise. This one also come up in our work. Suppose we have a variable z = ‘12,345.6’. What is its type? Convert it to a floating point number without the comma. Hint: Use tab completion to find a method to get rid of the comma.

Exercise. Take the list fruit and create a new list with the first letter capitalized. What method would you use to capitalize a string?

Exercise. Run the code

firstname = 'John'
lastname  = 'Lennon'
firstlast = firstname + ' ' + lastname

Find a method to replace the n’s in firstlast with asterisks.

Exercise. Consider the following string x = "How many characters and words are in this string?"

  • How many characters does x contain?

  • Convert x to a list of individual characters.

  • Convert x to a list of individual words.

  • How many words does x contain?

Exercise (challenging). Use tab completion and the Object inspector to find and apply a method to the string name that counts the number of appearances of the letter s. Use name = ‘Ulysses’ as a test case.

Are their other ways of doing this????

name = 'Ulysses'

Exercise. Consider the dictionary names = {'Dave': 'Backus', 'Chase': 'Coleman', 'Spencer': 'Lyon', 'Glenn': 'Okun'}

  • Use tab completion to get all the keys.

  • What type is the output above. Can you convert this to a list.

  • With your list, write a for loop over it, pass the keys to the dictionary, and print out the values.


Summary#

Congratulations! First, it’s amazing that you have made it this far. Reflect on what you knew before working through this notebook, namely what we did in notebook 1. Now reflect on what you can do…AMAZING!!! Let us summarize some key things that we covered.

  • Boolean variable and its operations: We conduct the comparsion operation on the right: x = 3 > 2, and we can assign the boolean values (True or False) to the variable x. We also learned how to compare two strings.

  • “if” conditional statement: it allows us to do different things depending on the result of a comparison or Boolean variable.

  • Slicing: we learn Forward and Backward counting conventions in a list, do you know when to select which? We also cover using : operator to select groups of data.

  • “for” Loop:

    • We can use for to loop through any iterable objects.

    • We talk a common built-in iterable object/data sturcture: range to help us with the data slicing/indexing.

  • Functions: we learn how to define and use customized functions.

  • Objects: a core concept in a object oriented programming language like python. It can help us understand how we can use . operations to call methods and attributes in an object.