Scripts, Modules, and
__name__ == "__main__"

In Python, a script is simply a file with Python code inside and a .py file extension. You can execute scripts as standalone files from the command line with the python3 command.

In Python, a module is a code file, like a script, that you import into another code file. You can import files into other files in your project or you can import files into a Python interactive shell session. The term “module” is used to describe reusable code.

Let’s take the following code as an example:

stocks.py

1
message = "We are in the middle of a bear market. Woo wee!"
2

3
prices = {
4
    "Monday": 100,
5
    "Tuesday": 200,
6
    "Wednesday": 300,
7
    "Thursday": 400,
8
    "Friday": 500,
9
}
10

11
def get_stock_price(day):
12
    print(f"The stock price for {day} is {prices[day]}.")

We can run this as a script:

python3 stocks.py

But nothing happens. It doesn’t throw any errors, so it seems to have worked. But it also doesn’t produce any output. It only defines objects. Let’s modify the code so it produces some output so we can see if our code actually works:

1
message = "We are in the middle of a bear market. Woo wee!"
2

3
prices = {
4
    "Monday": 100,
5
    "Tuesday": 200,
6
    "Wednesday": 300,
7
    "Thursday": 400,
8
    "Friday": 500,
9
}
10

11
def get_stock_price(day):
12
    print(f"The stock price for {day} is {prices[day]}.")
13

14
print(message)
15
get_stock_price("Monday")

When we run this as a script again we should see some output:

We are in the middle of a bear market. Woo wee!
The stock price for Monday is $100.

The problem is that if we want to use this code as an imported module, then we will also see the output:

Start an interactive Python shell:

python3

And import the module:

>>> import stocks
We are in the middle of a bear market. Woo wee!
The stock price for Monday is $100.

That is not typically the desired behavior. When you import a module, you probably don’t want to see output from the imported module.

Often when we are developing code, we want to run a file as a script that produces output so we can test the code as we are developing it. But once the code has been developed and tested, it would be nice to keep our test code around and turn off the output so the file can be imported and used in our project. We just don’t want the output from our tests showing up once the module has been imported. Well, Python let’s you do exactly that with the special dunder (double underscore) variable __name__.

Every Python file has a __name__ variable. When a Python file is run as a script, then the __name__ variable will be set to "__main__" because the standalone script is the “main” program that is running. On the other hand, if the file is imported as a module, then __name__ will be assigned the name of the file itself (which is typically the file name without the .py extension). For example, if our script.py file were imported as a module, then the __name__ variable for script.py would be "script".

This mechanism enables Python code to discern whether it’s being run as the main program (i.e. executed directly as a script) or imported as a module. What this means in practice is that you can conditionally run blocks of code based on the value of the __name__ variable. For example, update the code in stocks.py to match this:

1
message = "We are in the middle of a bear market. Woo wee!"
2

3
prices = {
4
    "Monday": 100,
5
    "Tuesday": 200,
6
    "Wednesday": 300,
7
    "Thursday": 400,
8
    "Friday": 500,
9
}
10

11
def get_stock_price(day):
12
    print(f"The stock price for {day} is {prices[day]}.")
13

14
print(f'__name__ == "{__name__}"')
15

16
if (__name__ == "__main__"):
17
    print(message)
18
    get_stock_price("Monday")

Now run the file as a script:

python3 stocks.py

__name__ == "__main__"
We are in the middle of a bear market. Woo wee!
The stock price for Monday is $100.

And run it as an imported module:

python3

>>> import stocks
__name__ == "stocks"

Notice how the output under the if statement only runs when __name__ == "__main__". How cool is that!

You can even pass arguments to the function test various scenarios. Update the code as in the following example. Notice that the print() function above the if statement has been removed and the code block under the if statement now captures arguments that are passed through the command line.

1
message = "We are in the middle of a bear market. Woo wee!"
2

3
prices = {
4
    "Monday": 100,
5
    "Tuesday": 200,
6
    "Wednesday": 300,
7
    "Thursday": 400,
8
    "Friday": 500,
9
}
10

11
def get_stock_price(day):
12
    print(f"The stock price for {day} is {prices[day]}.")
13

14
if (__name__ == "__main__"):
15
    import sys
16
    args = sys.argv
17
    # args[0] = current file
18
    # args[1] = function name
19
    # args[2:] = function args : (*unpacked)
20
    globals()[args[1]](*args[2:])

Run the file as a script, referencing the function name and passing an argument to the function:

python3 stocks.py get_stock_price "Friday"

The stock price for Friday is $500.

Run it as an imported module, calling the function and passing the function an argument:

python3

>>> from stocks import get_stock_price
>>> get_stock_price("Friday")
The stock price for Friday is $500.

Now you can use the __name__ variable to your advantage while developing Python code.

Sources: