Starting from:

$25

Lab 1 Python Functions

Welcome to Jupyter Notebook
Welcome to Jupyter Notebook, one of the many ways that you can use Python. Jupyter notebooks run lines of code in what are called cells. This makes it convenient to run certain lines of code and see the output of those lines of code in real time. To run a cell of code, simply press Shift + Enter.

Python Functions
Python is a dynamically typed language, meaning you don't have to declare the types of variables. These are determined at run time. Also, Python uses spacing to determine scopes and groupings. For example, when you write a function, it will look like this:

#Function definition
def helloWorld():
    print("Hello World")

#Calling the function
helloWorld()
Hello World
Note that the def means we are defining a function. The colon is necessary for defining what is part of the function. Also, everything that is part of the function needs to be spaced separately (convention is 4 spaces or a tab). Spacing is the number one reason for code not working.

Tuples
One of Python's useful capabilities is its ability to pass and return tuples. For example, if you need to return two pieces of information from a function, you simply can name the two pieces of information and treat them as a tuple.

def rectangleInfo(width, height):
    perimeter = 2*width + 2*height
    area = width * height
    return perimeter, area

myPerimeter, myArea = rectangleInfo(10,10)
print("My perimeter is", myPerimeter, "and my area is", myArea, ".")
My perimeter is 40 and my area is 100 .
Default Parameters
Lastly, Python has a very simple default parameter value system. To state a default parameter, simply state what that parameter would be equal to if no parameter is given in the function description.

def countByNum(startingNumber=1,stepSize=1,numIters=10):
    text = ""
    count = startingNumber
    for i in range(0,numIters):
        text += str(count)
        if i < numIters-1:
            text += ","
        count += stepSize
    print(text)

#The different ways to use default parameters 
countByNum()
countByNum(2, 2)
countByNum(stepSize=2)
1,2,3,4,5,6,7,8,9,10
2,4,6,8,10,12,14,16,18,20
1,3,5,7,9,11,13,15,17,19
Function 1: General Fibonaci Sequence
Write a function that takes in the number n (or num) and it returns the (n-1)th and nth Fibonacci numbers. Also, allow for the user to specify the 0th and 1st Fibonacci numbers that start off the sequence, but they should default to the standard ( n0 =1 and  n1 =1).

#Your code here
def fibonacci(num, n0=1, n1=1):
    sequence = [n0, n1]
    for n in range(num - 1):
        sequence.append(sequence[len(sequence) - 2] + sequence[len(sequence) - 1])
    return sequence[-2:]
To test that your code is working, try finding the  n5  and  n6  Fibonacci numbers for  n0=2  and  n1=2 . You should get 16 and 26 because the sequence would be (2, 2, 4, 6, 10, 16, 26). The second print statement is how we will grade that you completed the task. Do not delete any given test cases.

#Test Cases
print( fibonacci(6, 2, 2) )
print( fibonacci(10) )
print( fibonacci(24, 3, 5) )
[16, 26]
[55, 89]
[196418, 317811]
-------------------------------------------------------
Data Structures - Lists
Python has two primary types of data structures built in: lists and dictionaries. These data types are the most commonly used for Python methods and programming. Other types of data structures can be imported as needed. Let's start with lists.

myList = [] #Square brackets initialize a list

#Add elements to the list
myList.append(3)
myList.append(4)
myList.append(7)
#Insert the number 10 at the 0th index
myList.insert(0, 10)

print(myList)
[10, 3, 4, 7]
#List concatenation is very easy
print([1,2,3,4,5] + [6,7,8,9,10])
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
#Accessing an element in a list
print(myList[1])
#Grab the last element in a list
print(myList[-1])
#Grab all elements in a list
print(myList[:])
#Grap a certain section of the list  
print(myList[0:2])
[10, 3, 4, 7]
[10, 3]
Warning: Python excludes the last number in a range, as shown above. This is different from most common programming languages. To see this, run the following code.

a = range(0,10)
print(list(a))
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
Going back to lists, Python has a very powerful list accessing system known as slice notation. It can be summarized as

[ first element to include : first element to exclude : step ]

Some common examples are given below.

myList2 = list(range(0,10))
print(myList2)
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
#Grab every other element in the list
print(myList2[::2])

#Grab every other element for the first 5 numbers
print(myList2[0:5:2])

#Reverse the list
print(myList2[::-1])
[0, 2, 4, 6, 8]
[0, 2, 4]
[9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
In Python, for loops are designed with lists in mind. You can see some examples below.

myList3 = [1, 5, 8, 19, 7, 6]
total = 0

# You may be tempted to do this
length = len(myList3)

for i in range(0, length):
    num = myList3[i]
    total += num
    
print(total)
46
That is a very Java type way of doing list iteration, but there are better ways in Python. For example:

#It is much faster to do this
total = 0

for num in myList3:
    total += num

print(total)
46
Note that Python can give you elements of a list as the iterator through a for loop. This is very helpful in many problems.

For more help with lists, you can visit https://docs.python.org/3/tutorial/datastructures.html

Function 2: List Manipulation
Write a function called listShift. This function should take the second half of a list, reverse it, and reappend it to the front of the list. For example,

[1, 2, 3, 4, 5, 6, 7, 8, 9] would become [9,8,7,6,1,2,3,4,5]

As shown, odd number lists should not include the middle element in the reversed list.

Hint: This is a lot easier if you don't use a for loop.

#Your code here
def listShift(myList):
    split_index = -(len(myList)//-2)
    first_half = myList[:split_index]
    second_half = myList[split_index:]
    reverse_second_half = second_half[::-1]
    return reverse_second_half + first_half
#Test Case
print(listShift([1,2,3,4,5,6,7,8,9]))
print(listShift([10,9,8,7,6,5,4,3,2,1,10,9,8,7,6,5,4,3,2,1]))
[9, 8, 7, 6, 1, 2, 3, 4, 5]
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1]
-----------------------------------------------------
Data Structures - Dictionaries
We won't be using dictionaries as much in this class, but would be an injustice if you didn't get some exposure to them. They are one of the most powerful constructs in Python. The dictionary data structure is also sometimes known as a map data structure in other languages.

myDictionary = {} #Curly brackets initialize a dictionary

#Add elements to dictionary using key/value system
myDictionary["University"] = "BYU"
myDictionary["City"] = "Provo"

print(myDictionary)
{'University': 'BYU', 'City': 'Provo'}
#Another way to instatiate a dictionary
myDictionary2 = {'Name': 'Zara', 'Age': 7, 'Grade': '1'}
print(myDictionary2)

#Go through data in a dictionary
for key in myDictionary2:
    print(myDictionary2[key])

#Remove data
del myDictionary2["Grade"]
print(myDictionary2)

myDictionary2.clear()
print(myDictionary2)
{'Name': 'Zara', 'Age': 7, 'Grade': '1'}
Zara
7
1
{'Name': 'Zara', 'Age': 7}
{}
Python Classes
Python can use object oriented programming through the use of classes like most languages. However, the syntax for classes is very unique to Python.

Below is an example of a class in Python.

from math import pi

class Circle():
    
    def __init__(self, radius, center_x=0.0, center_y=0.0):
        self.radius = radius
        self.x = center_x
        self.y = center_y
        
    def getCircumference(self):
        return 2*pi*self.radius
    
    def getArea(self):
        return pi*self.radius**2
    
    def getArc(self, angle):
        return self.radius * angle
    
myCirc = Circle(25)
print(myCirc.getCircumference())
print(myCirc.getArea())
print(myCirc.getArc(1.5))
157.07963267948966
1963.4954084936207
37.5
Note the keyword class is used to start the definition. The constructor for the class is always defined within the init function. Any other functions can be named as needed.

Also, note that the keyword self must be passed into each function. This is where the variables for the class are stored. You can think of it similar to the this keyword in Java. However, note that this variable does not need to be passed in on call, only definition.

Inheritance
Classes can also inherit methods and properties from other classes. This can be done by placing the name of the super class in the parenthesis of the class defintion. These super classes can also have abstract methods by using the keyword pass.

class Shape():
    
    def getPerimeter(self):
        pass
    
    def getArea(self):
        pass
    
class Square(Shape):
    
    def __init__(self, size):
        self.size = size
    
    def getPerimeter(self):
        return 4*self.size
    
    def getArea(self):
        return self.size**2
    
    
mySquare = Square(10)
if isinstance(mySquare, Shape):
    print(mySquare.getPerimeter())
For more information on classes in Python, see https://docs.python.org/3/tutorial/classes.html

Functions 3: Push and Pop
Write your own class called MyPriorityQueue. This class should have two methods: push and pop. Push takes in a value and priority number and puts it in a dictionary. Pop returns the value with highest priority number and removes that value from the dictionary.

class MyPriorityQueue():
    
    #Your Code Here
    def __init__(self):
        self.dict = {}
    
    def push(self, value, priority):
        self.dict[priority] = value
    
    def pop(self):
        highest_prio_key = max(self.dict.keys())
        highest_prio_value = self.dict[highest_prio_key]
        del self.dict[highest_prio_key]
        return highest_prio_value
#Test Case
myQueue = MyPriorityQueue()
myQueue.push("were toiling upward in the night.", 2)
myQueue.push("The heights by great men reached and kept", 5)
myQueue.push("-Longfellow", 1)
myQueue.push("were not attained by sudden flight,", 4)
myQueue.push("but they, while their companions slept,", 3)
print(myQueue.pop())
print(myQueue.pop())
print(myQueue.pop())
print(myQueue.pop())
print(myQueue.pop())
The heights by great men reached and kept
were not attained by sudden flight,
but they, while their companions slept,
were toiling upward in the night.
-Longfellow
-----------------------------------------------------
Importing Packages in Python
Python has multiple ways to import packages to use in the system. The keywords you can use are import, from, and as.

import math
print(math.pi)

from math import pi
print(pi)

from math import pi as taco
print(taco)

from math import * #Import everything from the package
print(e)
3.141592653589793
3.141592653589793
3.141592653589793
2.718281828459045
One of the main packages we will use is called Numpy. It is a huge matrix processing library that is very helpful for image processing and graphics. The conventional import method looks like this.

import numpy as np
print(np.version.version)
1.17.2
Make sure that you have at least version 1.08 running. If you can't get the package to work, make sure that you run pip install numpy or conda install numpy in the command line according to the setup instructions.

Numpy allows you store matrices natively and do matrix operations in a single step.

Let's look at a simple matrix.

import numpy as np
a = np.matrix([[1, 2],[3,4]])

print(a)
---------------------------------------------------------------------------
ModuleNotFoundError                       Traceback (most recent call last)
/var/folders/7g/hr65gkl12213wbsg6s4lkmqm0000gq/T/ipykernel_57447/1300808961.py in <module>
----> 1 import numpy as np
      2 a = np.matrix([[1, 2],[3,4]])
      3 
      4 print(a)

ModuleNotFoundError: No module named 'numpy'
print(a[0,1]) #Row, Column zero-based indexing
2
print(a[:,1]) #Grab all rows and the second column
print()
print(a[0,:]) #Grab everything in the first row
[[2]
 [4]]

[[1 2]]
Note that all splice notation works with Numpy arrays.

You can also do operations on all elements of a Numpy array at the same time. This is shown below and is called vectorization (we will talk about this more later).

print(a + 1)
print()
print(3*a)
[[2 3]
 [4 5]]

[[ 3  6]
 [ 9 12]]
print(np.multiply(a,a)) #Element-wise multiply
print()
print(a*a) #True matrix multiply
[[ 1  4]
 [ 9 16]]

[[ 7 10]
 [15 22]]
There are plenty of Numpy operations that we are not covering, but we will see more of these as we go throughout the class. For more details, go to https://docs.scipy.org/doc/numpy/reference/ .

Now let's look at how we can import images as multidimensional arrays.

import matplotlib.pyplot as plt
geese = plt.imread('geese.jpg')
plt.imshow(geese)
plt.title("The Geese")
plt.show()

#Notice geese is a 3-dimensional Numpy array (row, col, rgb color).
#In this case, it is 256 x 256 x 3
#This means we can access it like any other list in Python.
print(geese[0,0,:])
[129 126 107]
Functions 4: Working with Numpy
Write the following three functions:

flip: Takes in a numpy array, flips it upside down and returns it. (Note: You don't need a for loop and you may not use np.flip)
green_channel: Takes in a 3-dimensional array and returns a 2-dimensional array containing only the green channel of the image.
#Your Code Here
import numpy as np
import matplotlib.pyplot as plt
import scipy.ndimage

def flip(image):
    return image[::-1, ::-1, ::-1]

def green_channel(image):
    print(image)
    return image
    return None
#Test Cases
#from scipy.ndimage import imread
geese = plt.imread('geese.jpg')

test1 = flip(geese)
plt.imshow(test1); plt.title("Flipped"); plt.show()

test2 = green_channel(geese)
plt.imshow(test2, cmap="Greys_r"); plt.title("The Grey Value of the Green Channel"); plt.show()

[[[129 126 107]
  [161 158 139]
  [171 168 149]
  ...
  [128 121 103]
  [183 176 158]
  [162 155 137]]

 [[170 167 148]
  [160 157 138]
  [166 163 144]
  ...
  [183 176 158]
  [170 163 145]
  [170 163 145]]

 [[159 156 137]
  [164 161 142]
  [144 141 122]
  ...
  [127 120 102]
  [118 111  93]
  [161 154 136]]

 ...

 [[ 75 103   0]
  [ 95 123   0]
  [119 148  22]
  ...
  [ 63  73  64]
  [ 79  91  79]
  [ 42  54  42]]

 [[138 164  41]
  [ 92 118   0]
  [117 144  15]
  ...
  [ 72  82  71]
  [ 86  98  86]
  [ 72  84  72]]

 [[180 206  81]
  [156 182  55]
  [117 144  15]
  ...
  [ 65  75  64]
  [ 84  94  83]
  [108 120 108]]]

More products