
The __name__ variable
You may have seen this line of code in other scripts and wonder what it is for. The conditional if __name__ == "__main__": plays a very important role when we are importing other functions as modules and is used to determine whether code should be executed or not. I don't expect you to fully understand this concept right away; the important thing here is to know that it exists and serves an important purpose.
A note on the terminology used in this section: When we say the script is "run directly" or is "directly executed", we are referring to the starting script from which all other functionality and process begins. It is the script being run, started, passed to the interpreter, c:/path-to-env/python.exe "script.py", etc.,.
When a Python script is executed, the interpreter process sets a few special variables, and one of them is __name__. If the script is being run directly, __name__ is set to "__main__". If the script is being imported as a module in another script, __name__ is set to the name of the script/module.
Why use if __name__ == "__main__":
?
This construct allows you to include code that you want to run only when the script is executed directly, and not executed when the script is imported by another script as a module. It is especially useful for including script function test code, setting exclusive script function arguments for one-off executions, and ensuring multiprocessing works correctly.
Consider the following two scripts:
script_A.py
import sys def greet(): print("Hello from script_A!") def update(script_name): print(f"updated: {script_name}") if __name__ == "__main__": print("Running script_A directly.") greet() update(__name__) # Print the sys modules to view the set names for module_name, module in sys.modules.items(): if hasattr(module, '__name__'): # Check if the module has a __name__ attribute print(f"Script A Module Name: {module_name}, __name__: {module.__name__}")
script_B.py
import sys import script_A print("Importing script_A at the top level...") script_A.greet() if __name__ == "__main__": print("Running script_B directly.") script_A.update(f"from {__name__}") # Print the script's sys modules to view the set names for module_name, module in sys.modules.items(): if hasattr(module, '__name__'): # Check if the module has a __name__ attribute print(f"Script B Module Name: {module_name}, __name__: {module.__name__}")
When script_A.py
is run directly, it produces the following output (Note that this is a shortened list, yours will be much longer):
Running script_A directly. Hello from script_A! updated: script_A ... Script A Module Name: abc, __name__: abc Script A Module Name: io, __name__: io Script A Module Name: __main__, __name__: __main__ Script A Module Name: _stat, __name__: _stat Script A Module Name: stat, __name__: stat ...
When script_B.py
is run directly, it imports script_A
and produces this output:
Importing script_A... Hello from script_A! Running script_B directly. updated: __main__ ... Module Name: script_A, __name__: script_A Module Name: script_B, __name__: __main__ ...
Multiprocessing Safety
Using the if __name__ == "__main__":
block is critical when working with multiprocessing, which we will be discussing in more detail in a later section so do not stress too much about what the multiprocessing code is doing, but focus on where the code is within the script. Consider this script:
safe_multiprocessing.py
import multiprocessing def worker_function(number): print(f"Worker {number} is working.") if __name__ == "__main__": print("Starting multiprocessing safely.") processes = [] for i in range(3): process = multiprocessing.Process(target=worker_function, args=(i,)) processes.append(process) process.start() for process in processes: process.join()
Running this script produces the following output, as the multiprocessing code executes safely within the __main__
block since code in this block is executed once:
Starting multiprocessing safely. Worker 0 is working. Worker 1 is working. Worker 2 is working.
If we wanted to use the safe_multiprocessing's worker_function method in another script, we would be able to do safely without executing the multiprocessing code block since the script's __name__ would be set to 'safe_multiprocessing' when imported into the other script. The imported script's (safe_multiprocessing in this case) if __name__ == '__main__':
would equate to False and prevent code within it from executing. We will see another variant of using a function within this conditional block in section 1.6.5.1, when we convert our HiHo Cherry-O game into a multprocessing script.
Common Pitfalls
If you omit the if __name__ == "__main__":
block in a multiprocessing script, you may encounter infinite recursion or a RuntimeError
. For example:
import multiprocessing def worker_function(number): print(f"Worker {number} is working.") # top-level multiprocessing code (not safe) processes = [] for i in range(3): process = multiprocessing.Process(target=worker_function, args=(i,)) processes.append(process) process.start() for process in processes: process.join()
Running this script can cause Python to repeatedly re-import the script and execute the unprotected top-level code each time it imports, leading to an infinite loop or crash.
If the script is imported as a module, any top level code (code not within a function, classes, or conditional) will execute when it is read in. If you forget to comment out test code, it may create a logical error by changing variables and paths. Even if unintended execution doesn’t cause issues, not using __name__ == "__main__" makes the script harder to maintain in the sense of compartmentalization. Developers expect reusable code (functions, classes) at the top, with executable code guarded inside if __name__ == "__main__" for testing or setting variables if the script is executed directly.
Key Takeaways
- The
if __name__ == "__main__":
construct separates script functionality from module functionality. - It provides reusable code in functions and Classes, allowing for either standalone execution or as a module.
- It prevents unintended execution of code during import and ensures safe multiprocessing.