Appendix 2: Structuring Complex Code

Adapted from: https://openbookproject.net/thinkcs/python/english3e/modules.html#creating-your-own-modules

Breaking a Long Code into Separate Modules

Up until now we have been keeping all our code in a single file. For large or complex programmes this can be difficult to manage. Fortunately it is possible to import functions from external modules, and use them in our current script. Putting values and functions in their own module is as simple as saving it in a separate Python script file, then importing the functions and variables using an import statement such as

import MY_MODULENAME as my

and accessing the objects within it using the DOT syntax:

NEW_VARNAME = my.VARIABLE

or

FNAME = my.FUNCTION

All we need to do to create our own modules is to save our script as a file with a .py extension (this is why you don’t use spaces in Python filenames!).

The following code is saved in a script saved as "mytools.py"in the same folder as the main notebook or python script (take a look at it).
It’s good practice to use the filename as the first line comment of the module:

#mytools.py
def remove_at(pos, seq):
    return seq[:pos] + seq[pos+1:]

We can now use our module in scripts we write, and access all the functions and variables in them. To do so, we must first import the module.

import mytools as my

s = "A string!"
print(my.remove_at(4, s))

Notice that the .py file extension is not used when importing.
Python expects the file names of Python modules to end in .py, so the file extension is not included in the import statement.

Note also that the module should usually be located in the same folder as your main Python script.

Namespaces in Modules

The use of modules makes it possible to break up very large programs into manageable sized parts, and to keep related parts together. In the following example the name of the module file is the comment on the first line.

First module, saved as "my_module.py" has these contents (take a look):

# my_module.py

question = "What is the meaning of Life, the Universe, and Everything?"
answer = 42

Second module, saved as "my_module2.py" looks like this:

# my_module2.py

question = "What is your quest?"
answer = "To seek the holy grail." 

We can now import both modules and access question and answer in each:

import my_module as my
import my_module2 as my2

print(my.question)
print(my2.question)
print()
print(my.answer)
print(my2.answer)

Exercise:

Create and use two of your own modules.

  • Go to the Jupyter Notebooks main menu page and then:

    1. Click “New” (top right),

    2. Set the name from untitled.txt to match the one below <NAME>.py

    3. cut and paste the code in (don’t forget to save it afterwards).

Create the following two python script files:

  • You will need to restart the kernel in your Notebook using the [⟳] button if you change the .py modules so that the new version is loaded using import.

Parameter module (use the filename in the head-line comment):

#my_params.py
import math

pi=math.pi

a=7.0
b=12.0

Module for my functions:

#my_functions.py
import my_params as myp

PI = myp.pi

def circle_area(r):
    return PI*r*r
  • Run the code below

import my_functions as funcs
import my_params as pars

print(funcs.PI)
print(pars.a)

print(funcs.circle_area(a))  
  • Correct the error in the cell below

### BEGIN SOLUTION
import my_functions as funcs
import my_params as pars

print(funcs.PI)
print(pars.a)

print(funcs.circle_area(pars.a))
### END SOLUTION

Click here for the correct way

Visibility of Variables

Note that a module cannot see the variables inside other modules, or in the main script unless we tell it about them. We can do this by having the modules themselves import things, or by declaring global variables.

Global variables can get confusing and are outside the scope of this introductory unit, but if you are interested there is lots of information available for your self-study (search for “Python global local variables”).

Exercise:

  1. Create a script named newmodule.py.

  2. Add variables myage set to your current age, and year set to the current year.

  3. Create another module named newmodule2.py.

  4. Add attributes myage set to 0, and year set to the year you were born.

  5. Now create a new script, import both of the modules above and write the following two lines:

    
    

print(“Have I had my birthday this year yet?\n”) print((newmodule.myage - newmodule2.myage) == (newmodule.year - newmodule2.year))

   * It should print `True` if you've had your birthday this year!
   

* **Dont forget to restart the kernel [⟳] if you change anything in the `.py` files and save**
### BEGIN SOLUTION
import newmodule, newmodule2
print("Have I had my birthday this year yet?\n")
print((newmodule.myage - newmodule2.myage) == (newmodule.year - newmodule2.year))
### END SOLUTION

You can also change variables.

E.g., if the above returned True set your age a year younger (or +=1 if it was False) using:

newmodule.myage -= 1 # takes one off the previous value
print(newmodule.myage)

and rerun the print lines again.

Model solution