Python Exercises lab 4

As with previous labs you are expected to write up your experiments and observations in your logbook.

4.1 Prerequisites and learning outcomes

Before you start this lab you are expected to know how to:

At the end of this lab you should be able to:

4.2 Writing your own functions using the def keyword.

a. Inspect the following program:

def grunt():
	print "growl"
def squark():
	print "squeak"
	print "honk"
print "howl"
squark()
print "beep"
grunt()
squark()

Write in your logbook the order in which the print statements will execute by writing the sequence of noises printed. Test whether you got the order correct, by copying and running the program. Try to see if you can step through the statements in a debugger.

Now write the missing words into the paragraph below taken from the word list:

sequentially functions block indented executed

Program statements are ________ in a defined order. Execution starts with the first non-_________ statement in the program which is not a function def. Execution continues __________ through each program _________ jumping into _________ when these are called.

And copy the correct paragraph into your logbook.

4.3 Providing parameters to functions to customise use at runtime.

The equation used to calculate a percentage is:

percent=N*100.0/total

where N is a number of items taken from a total, total is the total number of items and percent is the resulting percentage. e.g. if 34 students pass, out of 39 taking the module, the percentage pass rate is 34*100.0/39 which is 87.2% rounded to 1 DP.

a. Write a program percentage.py with a function percent() which has parameters N and total and calculates and prints the percentage. Call your function within your program twice, providing different values for N and total in each call e.g:

percent(34,39)
percent(12,24)

This program should print out the following values:

87.2%
50.0%

b. Write a function days_in_month() which, when given the number of the month as a parameter, e.g. 1 for January and 2 for February etc. it prints the number of days in the month e.g:

Month 1 has 31 days.
 

Save your program as months.py . For the first iteration of your design assume that it isn't a leap year.

c. In exercise 3.7 (b) you wrote a program called sqrt2.py. Create a new version called sqrt3.py which uses a function to calculate and print the square root. The number for which the root is calculated is passed as a parameter.

4.4 Return values from functions to the calling program unit.

a. Copy your percentage.py program, save it as percentage2.py and modify it so that the percent function does not print the percentage but returns it. Modify the calls

percent(34,39)
percent(12,24)

to

print percent(34,39)
p=percent(12,24)
print "%.1f%%" % p

so that the percentages returned are printed in the main program: in the first case directly, and in the second case by assigning the returned percentage to reference p.

Do the same with your square root function in sqrt3.py, so that the function returns the square root instead of printing it.

b. Copy the program months.py and save it as months2.py . Extend this so that your days_in_month() function also takes the year as a parameter and handles February in leap-years correctly. Your days_in_month() function will need to call another function is_leap() which should return a 1 for a leap year and a 0 for a non leap year. Hint: leap years are exactly divisible by 4 (e.g. 2004) except for years divisible by 100 (2100 isn't leap) except for years divisible by 400 (2000 is leap). You will need to pass is_leap() your year as a parameter.

c. Design another function called month_name() which takes the month number as a parameter and returns a string giving the name of the month. Test this function separately from months2.py until you are sure it works correctly. Next copy and paste the program: months2.py and your month_name() function into a new program: months3.py. Edit months3.py so that days_in_month() calls month_name() and prints it's output like this:

February 1996 has 29 days.

c. Design a function called intdiv() which takes a dividend and a divisor as parameters and returns the result and remainder (2 integers) as a tuple. E.G. given 9/2 equals 4 remainder 1:

9 is the dividend, 2 is the divisor (parameters), 4 is the result and 1 is the remainder (values returned as a tuple).

Write program statements which test this function by calling it twice with different parameters, and printing the returned values each time.

4.5 Use of local, global and built-in names within functions.

a. Copy, save as loc_global.py , inspect and run the following program:

def func1():
        N=2
        print "func1: %d" % N
def func2():
        print "func2: %d" % N
N=5
func1()
func2()
print "main: %d" % N

Fill in the missing words taken from the list into the paragraph below:

global references assigned objects local variable

Function func1() ___________ and printed a ________ variable called N. The main program assigned and printed a _________ ________ also called N. The local and global variables both called N are ___________ to different __________. Function func2() didn't assign to N and printed the _________ variable.

Write the completed paragraph into your logbook.

b. Design a program containing a function which assigns an object to a reference N which the function has declared as global. Print out the value of the reference in the main program. If the main program already has an N before calling the function which N is used ?

c. Inspect the following program override.py :

def func():
    def len(sequence):
        i=0
        for c in sequence:
            i+=1
        return ("length: ",i)
    print "func: length of abc is: " ,len("abc")
print "main: length of abc is: ", len("abc")
func()
print "main: length of abc is: ", len("abc")

When run this program outputs:

main: length of abc is:  3
func: length of abc is:  ('length: ', 3)
main: length of abc is:  3

Write in your logbook whether the function len() defined in func() overrides the built-in name len within the local scope of func or within the global scope of the program. How would you make func() override the global scope of the name len rather than just the local scope ?

Test if your answer works by copying, modifying and testing the above code.

4.6 Create your own Python module packaging functions and data

a. Copy and paste your days_in_month(), is_leap() and month_name() functions into a Python module called dates.py . Save months3.py as months4.py and edit it so that it imports and uses functions from your new module instead of its own source file.

b. Add a definition within your dates module:

days_in_full_year=(365,366)
 

This tuple can be indexed using the value 1 or 0 returned by dates.is_leap(), e.g:

>>> year=1900
>>> dinyear=dates.days_in_full_year[dates.is_leap(year)]
>>> print dinyear
365                          # 1900 wasn't a leap year

c. Add another function to dates.py called days_in_year() which takes year as a parameter, calls is_leap() to index the days_in_full_year tuple and returns the number of days in the year.

c. Also add the function get_date() to the dates module:

def get_date():
	day=int(raw_input("enter day of month"))
	month=int(raw_input("enter month number, 1=Jan, 12=Dec"))
	year=int(raw_input("enter year as 4 digits e.g: 2002"))
	return (day,month,year)

4.7 Import your own and other Python modules and use contained objects

a. Develop your program months5.py so that it prints the number of days between 2 dates input by the user, making use of objects within dates.py . Hint: this is probably easiest to achieve by counting the number of days between the earliest valid date, e.g: 1/1/1600 inclusive and each of the 2 dates, and then subtracting the smaller from the larger number. For each whole year add 365 or 366 to the total. For the last (incomplete) year add together the numbers of days for all complete months and the day number within the incomplete month.

b. Run the following commands from your Python interpreter

>>> from tkFileDialog import askopenfilename,asksaveasfilename
>>> file=askopenfilename()

This should bring up a standard GUI type file open dialog window. Select a text file (e.g. a Notepad .txt or Python program source file) using this dialog, click OK and then check that the dialog returns the path filename you have chosen by printing it:

>>> print file
/home/rich/python/stuff.txt
    # this might be c:\rich\python\stuff.txt on Windows

Next open this file and read it:

>>> fp=open(filename,"r")
>>> text=fp.read()
>>> print text
# contents of the text file you selected should be printed here
>>> fp.close()

c. Create a text object containing some words of your own. Assign a new filename using the asksaveasfilename() dialog. Open this file in write mode and write your text object to it. Test it worked using notepad or any text browser.

d. Find where on your system the tkFileDialog module is installed and browse the source code using a text editor or viewer. What other methods does it contain ?

This exercise was not written for a GUI programming course, but what you have done and seen should indicate what a Python programmer has to do and doesn't have to do to create an interesting application using library code.

Now fill in the missing words in the paragraph below from the list: programmers' wheel access reuse reinvent modular Python oriented.

_________ has _________ object-_________ facilities which give you direct _______ to other _____________ code. You can ______ this, so you don't have to _________ the _________.

4.8 Use the PYTHONPATH environment variable to store and find modules

a. Explore whether or not you have the ability to set environment variables on your system. If you really can't do this then you'll have to copy your Python modules into whichever directories you develop your projects in, which is bad practice, so try to do this exercise if you can.

b. Create a directory on your system, e.g: H:\python\modules and move (rename or cut and paste) your dates.py and dates.pyc files there (dates.pyc is a compiled version of the dates.py source file). Set the PYTHONPATH environment variable to a value which includes this directory, or add this directory to the PYTHONPATH environment variable if it already exists. Use colon (:) delimiters between multiple directory paths on Linux/Unix and semicolon (;) delimiters on Windows.

c. Import this module from Python programs and interpreters run from different directories. If import dates works, you now have a truly modular platform.