DEV Community

Cover image for Part Nine: Python Files and Modules
Simon Chalder
Simon Chalder

Posted on • Edited on

Part Nine: Python Files and Modules

Welcome to part nine. In this series I hope to introduce the basics of coding in Python for absolute beginners in an easy to follow and hopefully fun way. In this article we will look at the basics of importing and using modules in our code.


"But while you can always write 'spaghetti code' in a procedural language, object-oriented languages used poorly can add meatballs to your spaghetti." - Andrew Hunt


Modules


Simply put, a module is a Python file containing classes, methods, or functions we would like to use in our code.

Why is that useful?

If we have written projects using classes or functions which handle a particular thing such as displaying graphs, performing calculations, getting user input etc, we can save that code in its own Python file and keep it in our own code library for use in the future. Think back to article six where we made some basic calculator functions. They looked like this:

def add(num1, num2):
    print(num1 + num2)

def sub(num1, num2):
    print(num1 - num2)

def div(num1, num2):
    print(num1 / num2)

def mul(num1, num2):
    print(num1 * num2)
Enter fullscreen mode Exit fullscreen mode

Now, perhaps we think we may write another project in the future which requires a calculator, instead of writing out all of our functions again we can save this code in its own module.

We save this code in a new file as 'calc.py' and place it in the same folder as our new project file. We can name our modules anything we like as long as we remember to give it the '.py' extension at the end.

We can now start our new project as normal. To import the module we first place the module file in the same folder as our new project file.

├── project_folder
│   ├── new_project.py
│   ├── calc.py
Enter fullscreen mode Exit fullscreen mode

Next, we write the following at the beginning of the new project file:

import calc
Enter fullscreen mode Exit fullscreen mode

Now to access our functions in our new project we simply use the [modulename].[functionname]. For example:

import calc

print(calc.add(14, 28))

# Output
42
Enter fullscreen mode Exit fullscreen mode

Note that for example, if we only needed access to the division method for our project we can import only what we need:

from calc import div
Enter fullscreen mode Exit fullscreen mode

However, when we call a function this way, we omit the name of the module:

add(14, 28)

# Output
42
Enter fullscreen mode Exit fullscreen mode

Classes in Modules


Let's now place our calculator in its own class:

class calculator:
    def add(num1, num2):
        return num1 + num2

    def sub(num1, num2):
        return num1 - num2

    def div(num1, num2):
        return num1 / num2

    def mul(num1, num2):
        return num1 * num2
Enter fullscreen mode Exit fullscreen mode

To access the methods in our class, we need to include the class name in our method call so the syntax would be [modulename].[classname].[methodname]:

import calc

print(calc.calculator.sub(29, 6))

# Output
3
Enter fullscreen mode Exit fullscreen mode

Module Aliases


Some module names can be quite long or complicated. To make things easier to read we can import a module under a different name or alias. Say we had named our calculator module 'calculator.py', we can give it an alias when importing it to make it easier to work with:

import calculator as cal
Enter fullscreen mode Exit fullscreen mode

Now whenever we need to refer to the calculator module, we simply use 'cal' instead:

print(cal.add(12,8)

# Output
20
Enter fullscreen mode Exit fullscreen mode

Module Attributes


As well as classes, methods and functions, modules can also be used to store variables and data structures:

# calc.py

num1 = 10
num2 = 18
Enter fullscreen mode Exit fullscreen mode

To access these variables we simply use [modulename].[variable]:

# project.py

result = calc.num1 + calc.num2
print(result)

# Output
28
Enter fullscreen mode Exit fullscreen mode

Lists, tuples and dictionaries can be accessed in the same manner:

# calc.py

my_list = [12, 33, 109, 45]
Enter fullscreen mode Exit fullscreen mode
# project.py

print(calc.my_list[2])

# Output
109
Enter fullscreen mode Exit fullscreen mode

Viewing the contents of a module


Python has a built in function called dir() which allows us to view the contents of a module or object. This can be useful when we are unsure if a particular object or module contains the data we require. The dir() function will return the contents as a list and so to see it we must either print to the screen or use the returned data in a function.

Let's use our calc module to test this. We can add a couple of variables to our 'calc.py' file as well:

num1 = 10
num2 = 18

def add(num1, num2):
        return num1 + num2

def sub(num1, num2):
    return num1 - num2

def div(num1, num2):
    return num1 / num2

def mul(num1, num2):
    return num1 * num2
Enter fullscreen mode Exit fullscreen mode

We now print the returned results of our dir() function:

print(dir(calc))
Enter fullscreen mode Exit fullscreen mode

We get the following output:

['__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', 'add', 'div', 'mul', 'num1', 'num2', 'sub']
Enter fullscreen mode Exit fullscreen mode

What we have is a list of everything available to our module. Ignore everything with '__' either side and we can see the names of our functions as well as our 2 variables there too.

No great surprise right? I mean, we created the module so we know what's in it. However, where this becomes useful is when we deal with modules we did not create. This can be Python's built in modules and those written by other people.


Python's Built In Modules


"One man’s crappy software is another man’s full time job." - Jessica Gaston


Python ships with all manner of built in, handy modules. Here is a list if you would like to have a read through some of them.

We will cover a couple of them here so you can see how to use them but I encourage you to read around and try out as many as you can.

To begin let's look at the math module (boooooo maths!). Now, maybe your saying to yourself 'but I hate maths, what would I want to use that for?'. Well, the answer is quite simply that it does all of the hard work for you so you don't need to be a maths genius to work with numbers.

Firstly, go to the page linked above and scroll down to the 'math' module and click the link. What you will see is a list of all of the methods which are part of the 'math' module.

Let's import the math module to get started:

import math
Enter fullscreen mode Exit fullscreen mode

Simple enough. Scrolling down the methods page, I can see the pow() method. This method accepts 2 arguments, the first is our number, and the second is the power we wish to raise our number to. To call the method we simply use [modulename].[methodname]. So for example 3 to the power of 3 (3x3x3) is:

result = math.pow(3, 3)
print(result)

# Output
27
Enter fullscreen mode Exit fullscreen mode

Next let's try the square root method - sqrt(). Looking at the documentation, this method accepts a single argument and returns the square root of that argument:

result = math.sqrt(64)
print(result)

# Output
8
Enter fullscreen mode Exit fullscreen mode

Other methods of note in the math module are conversions for degree to radians and visa versa, trigonometric methods for calculating angles such as tree heights, and a method for returning pi for circumference and other circular calculations.

We can see the other methods which form the math module by using our dir() built in function:

print(dir(math))
Enter fullscreen mode Exit fullscreen mode

We get the following list as output:

['__doc__', '__loader__', '__name__', '__package__', '__spec__', 'acos', 'acosh', 'asin', 'asinh', 'atan', 'atan2', 'atanh', 'cbrt', 'ceil', 'comb', 'copysign', 'cos', 'cosh', 'degrees', 'dist', 'e', 'erf', 'erfc', 'exp', 'exp2', 'expm1', 'fabs', 'factorial', 'floor', 'fmod', 'frexp', 'fsum', 'gamma', 'gcd', 'hypot', 'inf', 'isclose', 'isfinite', 'isinf', 'isnan', 'isqrt', 'lcm', 'ldexp', 'lgamma', 'log', 'log10', 'log1p', 'log2', 'modf', 'nan', 
'nextafter', 'perm', 'pi', 'pow', 'prod', 'radians', 'remainder', 'sin', 'sinh', 'sqrt', 'tan', 'tanh', 'tau', 'trunc', 'ulp']
Enter fullscreen mode Exit fullscreen mode

Looking through the list we can see the 'pow' and 'sqrt' methods we used as well as all of the others.


For our second example, we will take a look at the random module. You may recall way back in my loops article that for the challenge, I generated some random numbers. Well, here is how we can do that.

Again we begin by importing the random module:

import random
Enter fullscreen mode Exit fullscreen mode

If we look through the methods available in the random module we will see randrange(). This method returns a random number between a set range. It accepts 2 arguments, the first is the lowest possible random number, the second is the highest. So for example if we want a random number between 1 and 100 we could do the following:

result = random.randrange(1, 100)
print(result)

# Output
23
Enter fullscreen mode Exit fullscreen mode

Finally, let's take a look at the random choice method - choice(). This method accepts a single argument which can be a list or tuple. The method will then randomly select one of the list items and return it:

my_list = [1,22,57,86,12]

result = random.choice(my_list)
print(result)

# Output
57
Enter fullscreen mode Exit fullscreen mode

Again let's take a look at this module with our dir() function:

print(dir(random))
Enter fullscreen mode Exit fullscreen mode

We get this list as an output:

['BPF', 'LOG4', 'NV_MAGICCONST', 'RECIP_BPF', 'Random', 'SG_MAGICCONST', 'SystemRandom', 'TWOPI', '_ONE', '_Sequence', '_Set', '__all__', '__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', '_accumulate', '_acos', '_bisect', '_ceil', '_cos', '_e', '_exp', '_floor', '_index', '_inst', '_isfinite', '_log', '_os', '_pi', '_random', '_repeat', '_sha512', '_sin', '_sqrt', '_test', '_test_generator', '_urandom', '_warn', 'betavariate', 'choice', 'choices', 'expovariate', 'gammavariate', 'gauss', 'getrandbits', 'getstate', 'lognormvariate', 'normalvariate', 'paretovariate', 'randbytes', 'randint', 'random', 'randrange', 
'sample', 'seed', 'setstate', 'shuffle', 'triangular', 'uniform', 'vonmisesvariate', 'weibullvariate']
Enter fullscreen mode Exit fullscreen mode

Conclusion


Hopefully this has started to demonstrate that many common things we may need for our projects are already contained in Python's built in modules which saves us the time of having to code this ourselves every time. By using our own modules, we can re-use our code in future projects to save us some time there too. In addition, we can now start to break up our code into separate files with each module having a particular purpose. We then simply import those files into our main project file to use their code. This has the advantage of making the code modular so that we know exactly where to look to work on a specific part of the application even if our project becomes very large overall.

In the next and final article, I want to demonstrate how you can import other people's modules into your code from the internet as well as taking a look at some modules which are likely to be of use to the land based sector.

As always, thank you for reading and I look forward to seeing you next time.

Simon.

Top comments (0)