Python modules: __name__ == __main__


In our previous post we reviewed how to apply the DRY principle (don’t repeat yourself) to our code and we learned how to create Python modules to avoid repeating ourselves (i.e. cutting-and-pasting code) across scripts and programs. In this post we will see how we can use our modules as a stand-alone program as well as useful functions that can be used by other scripts and programs.

__name__ == module_name

In our previous post we create a module called fitness.py that contained various functions. We also learned how to import our module to use it in our scripts and programs.

                Importing modules.

As we will see below, we can also include a special if statement to be able to run our module as a program. However, other than that, it is generally recommended to only include functions in modules. Why is that? When a module is imported, all the code it contains is run. This is what makes the various functions available in our script. However, if we have code that is not inside a function, it will be run when we import the module. For example, pretend we created a simple module:

# simple_module.py

def divide_by_two(x):
    return x/2

x = 6
print(divide_by_two(x))

Now pretend we import this module in an interactive Python session:

>> import simple_module
3
>> print(x)
6

By importing the module, all the code in the module is run. That is why we see the value 3 being printed immediately after we import the module. Also, our interactive Python session now has a variable called x, which was created when the module was run when it was imported.

When we import a module using one of the techniques described in our previous post, Python assigns the __name__ attribute of the module to the name of the module. For example, when we write import fitness at the start of a script, Python will set the __name__ attribute to fitness. This applies to all modules or packages that we import. For example:

import numpy
print(numpy.__name__)

This will print numpy.

__name__ == __main__

When we run a Python program by typing python <program_name.py> on the command line, Python assign the __name__ attribute to __main__. Therefore, we can add a bit of code at the end of our module to verify whether our module was run as a stand-alone program and do something useful. However, this does not preclude us from using the various functions in our module in other Python scripts or programs by using the import function.

Below is the fitness.py module, but with an if loop added at the bottom to determine whether the module is being run as a program from the command line, or if it is being imported to be used in another script or program.

def bmi_calc(weight_kg, height_m):
    """Calculate BMI from weight in kg and height in meters"""
    bmi = int(weight_kg / height_m**2)
    return bmi
    
def predict_max_HR(age):
    """Age predicted maximal heart rate"""
    max_HR = 208 - 0.7 * age
    return max_HR
    
def bp_risk(systolic, diastolic):
    """Categorises whether blood pressure is elevated, 
 stage 1 hypertension or stage 2 hypertension"""
    if systolic >= 120 and systolic < 130 and diastolic < 80:
        bprisk = 'elevated BP'
    elif (systolic >= 130 and systolic < 140) or (diastolic >= 80 and diastolic < 90):
        bprisk = 'stage 1 hypertension'
    elif systolic >= 140 or diastolic >= 90:
         bprisk = 'stage 2 hypertension'
    else:
        bprisk = 'invalid values'
    return bprisk
    
def print_results(initials, weight, height, age, systolic, diastolic):
    bmi = bmi_calc(weight, height)
    max_HR = predict_max_HR(age)
    bprisk = bp_risk(systolic, diastolic)
    print("\n\t" + initials)
    print("\tweight = {}kg".format(weight))
    print("\theight = {}m".format(height))
    print("\tage = {} years old".format(age))
    print("\tblood pressure = {}/{}".format(systolic, diastolic))
    print("\n\tbmi = {:3.1f}".format(bmi))
    print("\tpredicted maximal heart rate = {} bpm".format(max_HR))
    print("\tblood presure = " + bprisk)
    print("\n")

if __name__ == "__main__":
    try:
        initials, weight, height, age, systolic, diastolic = sys.argv[1:7]
    except ValueError:
        print('\nfitness.py requires 6 inputs:\n[initials, weight, height, age, systolic, diastolic].')
        print('\ne.g. >> python fitness.py MH 70 1.75 40 135 82\n\n')
        sys.exit()
    weight = float(weight)
    height = float(height)
    age = int(age)
    systolic = int(systolic)
    diastolic = int(diastolic)
    print_results(initials, weight, height, age, systolic, diastolic)
                sys.path.

If the module you are trying to import is not in the same folder as the script or program you are writing, we have to tell Python where to look for our module. By default, Python looks in the folders listed in sys.path. To see what folders are contained in this variable, we can run this simple piece of code:

>> import sys
>> print(sys.path)
['', 'current_directory/','/home/martin/lib/python3.6/site-packages', '/home/martin/anaconda3/lib/python36.zip', '/home/martin/anaconda3/lib/python3.6', '/home/martin/anaconda3/lib/python3.6/site-packages']

As we can see, sys.path contains a list of folders where Python searches for modules, starting from the current folder. We have two choices: place our module in one of the folders listed is sys.path or add the folder that contains our module to the sys.path variable.

How do we add the folder containing our module to sys.path? We have two options. First, we can add it manually at the start of our program or code:

import sys
modulefolder =/home/martin/programs/my_python_modules’
sys.path.insert(0, my_python_modules)

The above code adds the folder my_python_modules to the start of sys.path. We know it is the start because we are inserting our folder at position 0.

The second option is to add the folder containing our module to the PYTHONPATH environment variable. PYTHONPATH is a special variable on our computer system, and all folders listed in PYTHONPATH are automatically added to sys.path when a Python program starts.

On Mac and Linux systems, environment variables like PYTHONPATH are set in the .bashrc file in the home folder. For example, to add our example folder to PYTHONPATH we would add the following line to our .bashrc file in our home directory:

export PYTHONPATH=$HOME/programs/my_python_modules:$PYTHONPATH

The above line says that PYTHONPATH is now equal to our new added folder, plus all previous folders contained in PYTHONPATH. Multiple folders can be added if they are separated by a colon.

On Windows, we can run the following line on the command line (type cmd in the text box on the Windows Start menu) to add a folder for the current session:

set PYTHONPATH=C:\Users\Martin\programs\my_python_modules;%PYTHONPATH%

To add the folder permanently to our PYTHONPATH, we can add the above line to our autoexec.bat file.

Another approach is to change these things using a graphical user interface:
My Computer > Properties > Advanced System Settings > Environment Variables >
Create a PYTHONPATH system variable and add C:\Users\Martin\programs\my_python_modules;%PYTHONPATH% under the variable value.

As the print() statement indicates, we can now run this module as a program if we provide the 6 required inputs. The five numerical values are imported as text (i.e. strings), so we first have to convert these to numerical values (e.g. weight = float(weight)). We then call our function print_results() which will compute various things and print an informative message. Below is an example:

# Try calling our function without enough inputs
$ python fitness.py gg 55

fitness.py requires 5 inputs:
[initials, weight, height, age, systolic, diastolic].
e.g. >> python fitness.py MH 70 1.75 40 135 82

# Call our function will all the required inputs
$ python fitness.py MH 75 1.75 40 127 80

    MH
    weight = 75.0kg
    height = 1.75m
    age = 40 years old
    blood pressure = 127/80

    bmi = 24.5
    predicted maximal heart rate = 180.0 bpm
    blood presure = stage 1 hypertension

Summary

We have learned how to put an additional if '__name__' is '__main__' statement at the end of our module to allow us to use it as a program from the command line. In our next post we will learn how to group various modules together to form a Python package.

 

 

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s