Module versus Script in Python

Trey Hunner smiling in a t-shirt against a yellow wall
Trey Hunner
4 min. read Python 3.8—3.12
Share
Copied to clipboard.
Tags

Python programmers often make a distinction between .py files that represent "modules" vs "scripts" (aka "programs").

What's a script?

A script or program is a .py file that's meant to be run directly.

Here's an extremely simple script that prints out "Howdy user":

print("Howdy user")

If that file was called hello.py, we could run it from the command-line like this:

$ python3 hello.py
Howdy user

What's a module?

A module is a .py file that's meant to be imported by other .py files. Modules should contain helpful functions, classes, or variables pointing to useful data.

Here's a module that has a single function, greet, within it:

def greet(name):
    print("Howdy", name)

If this module was named salutations.py, we could import and use the greet function within it from the REPL like this:

>>> import salutations
>>> salutations.greet("Trey")
Howdy Trey

Or we could import our salutations module (and use its greet function) within our hello.py file:

from salutations import greet

name = input("What would you like me to call you? ")
print("Noted!")
greet(name)

This way when hello.py is run, the user will be prompted to enter their name and then the greet function (which lives in the salutations module) will be run:

$ python3 hello.py
What would you like me to call you? Trey
Noted!
Howdy Trey

You can read more on importing here.

Scripts are modules

All .py files are Python modules, even scripts. Scripts are modules that act as the entry point to our Python process.

You can prove to yourself that scripts are modules by importing a .py file that's meant to be used as a script:

>>> import hello
What would you like me to call you? Trey
Noted!
Howdy Trey

Importing a module runs all the code in that module and sticks it into a module object.

You could even try running a module from the command-line. Usually that just defines a bunch of functions and exits (since modules aren't supposed to have side effects, meaning no printing/prompting/etc at import time):

$ python3 salutations.py

Making a script that acts nicely when used as a module (when imported)

Most scripts aren't meant to be imported as modules (it's a bit odd to see something start happening simply because a module was imported).

If you want to make a script that will print things out and do useful tasks when run from the command-line but won't do those things when imported, you'll need to somehow distinguish between two states:

  1. Am I currently being imported by another module?
  2. Or am I the entry point the whole Python process (I'm being run as a script)

Every module has a __name__ variable within it to help answer this question. The __name__ variable has two possible values:

  1. When our module is imported by another module, __name__ will be set to the name of our module (e.g. the string 'greet')
  2. When our module is being run from the command-line, __name__ will be set to the string '__main__'

Instead of making two files, salutations.py (meant to be imported) and hello.py (meant to be run from the command-line) we could make one file that does both if we modify salutations.py like this:

def greet(name):
    print("Howdy", name)

if __name__ == "__main__":
    name = input("What would you like me to call you? ")
    print("Noted!")
    greet(name)

Then when we import salutations, we'll have access to a greet function (but we won't be prompted for input and nothing will be printed on import):

>>> import salutations
>>> salutations.greet("Trey")
Howdy Trey

And if we run salutations.py from the command-line we'll be prompted for input and text will be printed:

$ python3 salutations.py
What would you like me to call you? Trey
Noted!
Howdy Trey

You can read more on why Python scripts use that __name__ check here.

The REPL is a module!

Interestingly, this __name__ thing even exists in the Python REPL.

When you run python3 with no arguments, you're launching the Python REPL. Every Python process needs an entry point module. When you're in the REPL, you're creating that entry point module as you write code. As you type code at the REPL, you're basically writing a script on-the-fly.

Since the code we write at the REPL acts as our entry point Python module, __name__ is __main__:

>>> __name__
'__main__'

The __name__ variable in the REPL is set to __main__ because as we type code at the REPL, we're basically poking around within the entry point to our Python process.

If you pass Python the -i argument as you run a script, Python will run all the code within your script and then it will drop you into a Python REPL that's inside your module.

$ python3 -i salutations.py
What would you like me to call you? Trey
Noted!
Howdy Trey
>>> name
'Trey'
>>> greet
<function greet at 0x7f4b0b8d5040>

Normally the REPL makes a new empty module for you to start writing your code in. When running a module interactively, the REPL will instead drop you into the module you gave it, almost as if each command typed at the REPL added more code to that module (not modifying the original .py file though, just the current Python process).

More on modules and scripts

For more see articles on modules in Python and articles on command-line interfaces in Python.

A Python Tip Every Week

Need to fill-in gaps in your Python skills? I send weekly emails designed to do just that.