Lab 6: Python

Goals

Your first Python Program - Hello World

In lab, we will use a text editor and the command line to write and run programs. We will not use Eclipse.

Open a new python file, hello.py, using a text editor.

Enter the code

 print("Hello, world!") 

into the hello.py file and press save. Now run this program from the command line with the command

 python hello.py 

Functions

The syntax to write a max function in Java looks like the following:

public static int max(int a, int b){
    if (a > b){
        return a;
    }
    else{
        return b;
    }
}

The equivalent function defined in Python looks like the following:

def max(a, b):
    if (a > b):
        return a
    else:
        return b

Differences to note:

  1. The def keyword specifies the start of a function
  2. We still list inputs in the normal place - however they are not given a type
  3. Curly braces {} have been replaced by colons and indentation. After every statement that used to use curly braces in Java, we now place a colon. The indentation rules you learned in Java still apply only now they are mandatory. Improperly indented code will not run correctly.

In the last lab we showed you a recursive factorial function that looked like the following

public static int factorial(int n){
    if (n==1) {
        return 1;
    } else {
        return n * fact(n-1);
    }
}

Use your text editor to create a new file, factorial.py and, within this file define the equivalent factorial function in Python. It should look relatively similar to the code above. After your function definition print out the result of calling the factorial function on the number 5.

print(factorial(5))

Run this file with the command:

 python factorial.py 

If your function works correctly, you should see the value 120.

Loops

While loops in Python are identical to while loops in Java after you replace curly braces with colons and indentation. Consider the following while loop that prints out every number up to 10.

int i = 1;
while(i < 10){
    System.out.println(i);
    i += 1;
}

The equivalent function defined in Python looks like the following:

i = 1
while(i < 10):
    print(i)
    i = i + 1

Inside factorial.py write a while loop that prints out the first 10 numbers and their factorials using the factorial function.

Exercises

Open up a new python file in your text editor named squares.py. Try and do the following:

Interactive Python

So far we have used Python much like we used Java. We write programs in a text editor and then run them from a terminal window. Python offers an alternative to this approach. Python can be run interactively. Run the command ipython from within your lab6 directory. If this is your first time running ipython a welcome message will appear. You can press Enter to get rid of it.

ipython is an interactive Python terminal. You can type commands in directly and they will be run immediately. Try typing in the following commands from our first exercise:

name = "Alice"
print("Hello "+name)

The result should print immediately to the screen. ipython can be treated as a very fancy calculator. Try the following commands:

from math import sin, cos, pi
theta = 3*pi / 2
sin(theta)

Notice that the first step is to import functions and variables (like sin, cos, pi) from a library (like math). Also, note that function sin(theta) prints out the value sin(theta). Simply typing an expression into ipython will cause it to be evaluated and printed to the screen.

Importing your own code into ipython

We can also import our own code into ipython. Import the printSquares function from squares.py with the following command.

from squares import printSquares

The printSquares function is now available in ipython. Try it out by printing the squares of 1 to 20.

Change the printSquares function in squares.py to print out the cubes instead of the squares (just leave the same name for now). Save your file and then re-import the function

from squares import printSquares
printSquares(5)

What happens? Does it work as you expect?

Unfortunately ipython does not pick up new changes to your file once you have imported it. To solve this problem, we use the run command

run squares.py

The run command is just like import but it will reload the file. Run the squares.py file and ensure that your printSquares function is now printing cubes instead of squares as you expect.

In order to exit the interactive python terminal type exit().

A Standard Workflow

When working on Python programs it is traditional to have two windows open, a text editor and an ipython terminal. We switch back and forth between these two much more frequently than in Java. We write functions in the text editor (writing functions in ipython is a pain) and then try them out in ipython. The standard workflow is something like the following:

  1. Experiment in ipython to get an idea of how a function should work.
  2. Use a text editor to write a first draft of the function in a .py file.
  3. Run a file from ipython to load your work. run name_of_your_file.py
  4. Use the function from within ipython. name_of_your_function(). Discover that your function doesn't work.
  5. Fix errors in the .py file and click save.
  6. Re-run the file in ipython to update the changes. run name_of_your_file.py
  7. Repeat until your code is working as intended.

Lists and Foreach loops

In computer science we often want to represent many variables at once. In Java we usually used arrays and occasionally used lists. In Python this is reversed, we always use lists and never use arrays. Fortunately, the Python list object is both very powerful and very easy to use.

Look at the examples given in the brief standard Python tutorial on lists. Notice

  1. That lists can contain elements of different types,
  2. The familiar array-like syntax for retrieving or setting the ith element of a list,
  3. That the function len can be used to obtain the length of a list, and
  4. That sublists can be accessed or assigned to using slices like 0:2.

Java for loops were centered around arrays. Python uses foreach loops. These are easier for lists but very different from standard for loops. Java for loops have the structure:

for( --starting statement--; --condition--; --end-of-loop-action--)
{
    ...
}

The Python foreach loop has the structure

for item in list:
    --do stuff with item--

This construct is similar to the foreach construct in Java.

Consider the following example,

--input--
listOfWords = ['Alice', 'Bob', 'Charlie']
for word in listOfWords:
    print word, len(word)

--output--
Alice 5
Bob 3
Charlie 7

In Java we usually created a counting variable int i and used it to access each of the elements of an array one at a time. The Python foreach loop achieves the same result but it skips the int i step - it delivers the elements of a list directly to you.

numbers = [5,2,3,1]
for x in numbers:       # x takes on each of the values of numbers
    print(x**2)         # prints the square of each number in the list

In the above example we print a value for each element in a list. Printing is rarely useful in computer programming - it's much better to save results to a variable. In the following example we save the same numbers into a list.

input  = [5,2,3,1]
output = []                     # Make an empty list
for x in input:
    output.append(x**2)         # Append x squared to the end the list

This is a very common pattern. We take each element in some input list, change it (here by squaring), and append the result onto the end of an output list. We've used the variable names input and output here just for clarity. We might choose better names in practice.

numbers = [5,2,3,1]
squares = []                     # Make an empty list
for x in numbers:
    squares.append(x**2)         # Append x squared to the end the list

Run this example in ipython and print out the result of squares. Did it run as you expected? When writing for loops in ipython you will need to press enter a few times when you're finished with the loop. Pressing enter twice is like the closing curly brace in ipython.

Exercises

Open up a new file list2.py in your lab6 directory (please ignore list.py). Write the following functions into that file. After you write a function run it in ipython and test it with some sample inputs. Your goal is to become familiar with writing functions and with using an editor and ipython simultaneously.

Stock Prices

In this exercise we will get data from Yahoo!'s financial database of stock prices. We'll get stock data directly from the internet.

Look at this python module to see the functions we can use. This code was written by a Python programmer who published his work so others can use it. This open source culture of sharing code is very common in Python and is one of the reasons for the language's popularity.

Import any functions from the ystockquote into ipython that interest you. If you'd like you can import them all using

from ystockquote import * 

This import works only because ystockquote.py is in the same directory from which we started ipython

Tab and Help

Now type in just get_ and press tab. This will list all functions that start with get_.

In [9]: get_
get_200day_moving_avg            get_historical_prices
get_50day_moving_avg             get_ipython
get_52_week_high                 get_market_cap
get_52_week_low                  get_price
get_all                          get_price_book_ratio
get_avg_daily_volume             get_price_earnings_growth_ratio
get_book_value                   get_price_earnings_ratio
get_change                       get_price_sales_ratio
get_dividend_per_share           get_short_ratio
get_dividend_yield               get_stock_exchange
get_earnings_per_share           get_volume
get_ebitda                       

If you press p and tab again it will auto-complete to get_price for you. Using tab for auto-completion can save you time and reduce frustration.

Lets ask for help on the get_price function using. You can press q to exit.

help(get_price)

Get the price of your favorite stock. Some examples for the tech-giants are "GOOG", "AAPL", "AMZN" but anything that Yahoo! tracks should be accessible. This is a real-time stock quote (accurate to a few seconds). Notice how the result is a string. While nice, strings probably aren't the most appropriate type for this kind of numeric data. Convert the result to a float (like a double) using the float function.

In [1]: float('123') 
Out[1]: 123.0

Verify that you can use float and get_price together to get the current price of a stock as a number and not as a string.

The ystockquote library also contains a function get_historical_prices that returns the price of a stock for a specified time range. Use the help function on get_historical_prices to see an example. get_historical_prices returns a list of lists. Each element of the result is another list. This is like a two dimensional array. We're going to work with the data returned by this function to produce the stock-price plot above. Get the prices of Google from January 1st 2009 to December 31st 2009 using the code snipped below in ipython.

In [2]: stockData = get_historical_prices('GOOG', '20090101','20091231')

In [3]: type(stockData)
Out[3]: list

In [4]: len(stockData)
Out[4]: 253

The type of stockData is list and that it's fairly long (there is one element for each market day of the year). Lets print out the fourth element of this list

In [6]: stockData[4]
Out[6]: ['2009-12-28', '621.66', '625.99', '618.48', '622.87', '1697900', '622.8']

What is the type of stockData[4]? What is the type of stockData[4][1]? We can see that stockData is a list of lists of strings. What do these strings/numbers mean?

We print out the first five rows all at once

In [8]: stockData[0:5]        # print out first five elements of stockData
Out[8]:
[['Date', 'Open', 'High', 'Low', 'Close', 'Volume', 'Adj Clos'],
['2009-12-31', '624.75', '625.40', '619.98', '619.98', '1219800', '619.9'],
['2009-12-30', '618.50', '622.73', '618.01', '622.73', '1465600', '622.7'],
['2009-12-29', '624.74', '624.84', '618.29', '619.40', '1424800', '619.4'],
['2009-12-28', '621.66', '625.99', '618.48', '622.87', '1697900', '622.8']]

We used a "slice" to print out all elements of stockData from 0 to 5 at once. We see that the zeroth element of stockData is different from the rest. It contains the titles of each of the columns. This is very common in statistical data.

Our task today is to plot the closing prices as shown in the figure above. This will be easy once we have a list of the correct float/double values. Thus, we want a single list of floats that looks like the following

[619.98, 622.73, 619.40, 622.87, ... ]

We will accomplish this task by writing a function that turns one of the lines in stockData into the corresponding float value. Thus, we want a transformation that does the following

['2009-12-28', '621.66', '625.99', '618.48', '622.87', '1697900', '622.8']  => 622.87

We can then apply this function to each line in stockData using a for loop to obtain all the closing values.

Exercises

These steps are very detailed. If you feel comfortable with Python feel free to skip around.

  1. Open up a new file called stocks.py
  2. At the top of this file import the get_historical_prices function from the ystockquote library
  3. On the next line get the historical data from Google for the entire year of 2009 and store this in a variable stockData. We did this in the example.
  4. run stocks.py in ipython and ensure that this worked. The variable stockData should be available
  5. The first line of stockData has the header. These words will get in the way of our code, lets remove them with stockData = stockData[1:]
  6. Run your file in ipython and ensure that the header was removed from stockData by printing out the first five lines.
  7. Make a new function getClosingPrice that takes in a list like ['2009-12-28', '621.66', '625.99', '618.48', '622.87', '1697900', '622.8']
    and returns the number that corresponds to the closing price. Use the float function to ensure that getClosingPrice returns the number as a float and not as a string (we will need this in a minute). This function should be very small.
  8. Run your file in ipython and ensure that getClosingPrice works. Try it on a few elements of stockData
  9. Use getClosingPrice in stocks.py to make a new list of closing prices for stockData. This should be very similar to the squares example from earlier in the lab
  10. Run your file in ipython and ensure that this worked (you should become comfortable with this edit-file-try-in-ipython pattern)
  11. We now want to plot this list. Before we do that we'll need to restart ipython in plotting mode. Close ipython with exit() and then restart it with the terminal command ipython --pylab
  12. Rerun your file and plot this list in ipython with the plot function (see section below). Does it look like the picture? Did Google do well or poorly in 2009? Does its price increase or decrease? Is something wrong? Look at the dates inside stockData
  13. Oh no! They're in reverse order! You can reverse a list L by typing L = list(reversed(L))
  14. Plot this list and make sure it looks like what you expect (Google did quite well in 2009)
  15. Now that we have all the code necessary lets clean up stocks.py. It's bad style to have code in a .py file that is outside of a function. Make a new function def closingPrices(ticker) that takes in a ticker symbol like 'GOOG' and returns a list of floats in correct order.
  16. Make a function plotStock that takes in a ticker symbol like 'GOOG' and plots it to the screen with plot. You will need to import the plot function from the pylab library in stocks.py.

Plotting

When we ran IPython we did it with the command

ipython --pylab 

The second entry --pylab opened ipython in plotting mode. In particular it imported all of the functionality of the matplotlib library, the standard plotting library for Python.

Matplotlib has a number of very useful functions. You might want to take a look at their help stings. In particular today we will use

    plot    -- plot a list of floats
    title   -- add a title
    xlabel  -- add a label on the x axis
    ylabel  -- add a label on the y axis
    cla     -- clear the plot

plot is particularly useful. If you give it a list of floats it will plot them on the screen. If you give it two lists of floats it will plot them as X-Y coordinates. There are a number of options to select color, line style, etc...

If you have successfully completed the last section you should have such a list of floats. Call plot on it from within IPython. Use title, xlabel, and ylabel to add some text to your figure.