Register to get access to free programming courses with interactive exercises

Running modules and packages Python: Setting up the environment

Suppose we have a code file that we run as a script. The file grows, and functions and other definitions appear.

At some point, we want to reuse a function from this module in another module. So you have to import. In this lesson, we'll understand how importing scripts works.

Importing scripts

Let's simulate the situation described above. It is what the original script will look like:

# file <first_script.py>

def greet(who):
    print(f'Hello, {who}!')

greet('Bob')
greet('Ann')

Now let's look at the new script in which we want to reuse the greet function from the first script:

# file <second_script.py>

from first_script import greet

greet('Thomas')

Let's run the first script and then the second script. Both files are in the current directory:

python3 first_script.py

Hello, Bob!
Hello, Ann!

python3 second_script.py

Hello, Bob!
Hello, Ann!
Hello, Thomas!

When the second script ran, the first script ran as well, even though we only imported one function from it. It is the price of simplicity in scripting.

The file of the first script contains definitions and direct actions, so when you load the file when importing the module, the interpreter will perform these actions.

Imagine we imported a script that didn't just print something to the screen but also deleted some files.

It turns out we need to somehow distinguish between two types of situations:

  1. If the module works as a script, we need to perform side actions
  2. If we import the module or its contents, we don't perform any side actions

The __name__ variable

Let us look at the import mechanism when loading the module for the first time. Specifically, we mean the first time for the current interpreter run. During the first load, the interpreter adds some variables to the module. There are quite a few of these variables, but we're only interested in one — the __name__ variable for now.

The variable has an unusual name with four whole underscores. These names usually have some special meaning in Python code. An experienced developer usually remembers a dozen of these variables by heart. It is why people like to ask about these variables at job interviews.

Let's see what the __name__ variable stores in each case:

  • If a regular import occurs, this variable contains the full name of the module
  • If it's launched as a script, the variable gets the '__main__' string

By looking at the value of this variable, we can distinguish between running as a script and importing. The word main is used in many languages to name a function that's called automatically when the program starts. That's why Python uses the word in a similar sense.

Let's go back to our example and rewrite first_script.py using this new knowledge:

# file <first_script.py>

def greet(who):
    print(f'Hello, {who}!')

if __name__ == '__main__':
    greet('Bob')
    greet('Ann')

Our script won't greet Bob and Ann if we import the module.

The main function

Our first_script.py is already good enough, but we can improve it.

The body of the if __name__… condition lists the actions performed when the script runs. Over time, we can end up with many of these actions. It's common to have situations where we reuse this code piece. Therefore, we have a convention: in the body of the if __name__… condition, we only make one call to the function without main arguments.

The function is declared above in the same module. It's generally considered better practice to place the condition at the very end of the script module.

Taking into account all the recommendations described above, the final version of the first_script.py script will look like this:

#!/usr/bin/env python3

def greet(who):
    print(f'Hello, {who}!')

def main():
    greet('Bob')
    greet('Ann')

if __name__ == '__main__':
    main()

You can also have this script:

  • Run directly
  • Run from other scripts by calling the main function
  • Use as a library

Runnable packages

Let's consider a slightly unusual case but still often encountered: launching a package.

It might seem that since the __init__.py module is always loaded when the package is loaded, we should place the main function and the condition there. But launching packages is implemented slightly differently: when a package is loaded, the interpreter looks for __main__.py and executes it as a script. We won't go into the reasons here. Remember that executable packages always contain the __main__.py script.

When might I need to run a package? Let's take one small script as an example. In the end, we end up with more and more code, so much so that it has become impossible to maintain this script. Let us imagine that we decided to turn one module into a package containing modules. But how can we launch this package? It is where the __main__.py module helps us.


Recommended materials

  1. A complete list of what the importing machine adds to the module
  2. The name '__main__' and its meaning

Are there any more questions? Ask them in the Discussion section.

The Hexlet support team or other students will answer you.

About Hexlet learning process

For full access to the course you need a professional subscription.

A professional subscription will give you full access to all Hexlet courses, projects and lifetime access to the theory of lessons learned. You can cancel your subscription at any time.

Get access
130
courses
1000
exercises
2000+
hours of theory
3200
tests

Sign up

Programming courses for beginners and experienced developers. Start training for free

  • 130 courses, 2000+ hours of theory
  • 1000 practical tasks in a browser
  • 360 000 students
By sending this form, you agree to our Personal Policy and Service Conditions

Our graduates work in companies:

<span class="translation_missing" title="translation missing: en.web.courses.lessons.registration.bookmate">Bookmate</span>
<span class="translation_missing" title="translation missing: en.web.courses.lessons.registration.healthsamurai">Healthsamurai</span>
<span class="translation_missing" title="translation missing: en.web.courses.lessons.registration.dualboot">Dualboot</span>
<span class="translation_missing" title="translation missing: en.web.courses.lessons.registration.abbyy">Abbyy</span>
Suggested learning programs
profession
new
Developing web applications with Django
10 months
from scratch
under development
Start at any time

Use Hexlet to the fullest extent!

  • Ask questions about the lesson
  • Test your knowledge in quizzes
  • Practice in your browser
  • Track your progress

Sign up or sign in

By sending this form, you agree to our Personal Policy and Service Conditions
Toto Image

Ask questions if you want to discuss a theory or an exercise. Hexlet Support Team and experienced community members can help find answers and solve a problem.