Executing a Module
In this lesson, you’ll learn about executing a module as a script. Any .py
file that contains a module is essentially also a Python script, and there isn’t any reason it can’t be executed like one.
Here’s mod.py
, as it was defined earlier:
s = "Computers are useless. They can only give you answers."
a = [100, 200, 300]
def printy(arg):
print(f'arg = {arg}')
class Classy:
pass
This can be run as a script:
$ python3 mod.py
There are no errors, so it apparently worked. Granted, it’s not very interesting. As it is written, it only defines objects. It doesn’t do anything with them, and it doesn’t generate any output.
Let’s modify the above Python module so it does generate some output when run as a script:
s = "Computers are useless. They can only give you answers."
a = [100, 200, 300]
def printy(arg):
print(f'arg = {arg}')
class Classy:
pass
print(s)
print(a)
printy('Good Day Sir!')
x = Classy()
print(x)
Now it should be a little more interesting:
$ python3 mod.py
Computers are useless. They can only give you answers.
[100, 200, 300]
arg = Good Day Sir!
<__main__.Classy object at 0x10f7a35f8>
Unfortunately, now it also generates output when imported as a module:
>>> import mod
Computers are useless. They can only give you answers.
[100, 200, 300]
arg = Good Day Sir!
<__main__.Classy object at 0x111324748>
This is probably not what you want. It isn’t usual for a module to generate output when it is imported. Wouldn’t it be nice if you could distinguish between when the file is loaded as a module and when it is run as a standalone script? Ask and ye shall receive!
When a .py
file is imported as a module, Python sets the special dunder variable __name__
to the name of the module. However, if a file is run as a standalone script, __name__
is (creatively) set to the string '__main__'
. Using this fact, you can see which is the case at run-time and change behavior accordingly:
s = "Computers are useless. They can only give you answers."
a = [100, 200, 300]
def printy(arg):
print(f'arg = {arg}')
class Classy:
pass
if (__name__ == '__main__'):
print(s)
print(a)
printy('Good Day Sir!')
x = Classy()
print(x)
Now, if you run as a script, you get output:
$ python3 mod.py
Computers are useless. They can only give you answers.
[100, 200, 300]
arg = Good Day Sir!
<__main__.Classy object at 0x100a5d5f8>
But if you import as a module, you don’t:
>>> import mod
>>> dir()
['__builtins__', '__doc__', '__loader__', '__name__', '__package__',
'__spec__', 'help', 'mod']
>>> __name__
'__main__'
>>> mod.__name__
'mod'
Modules are often designed with the capability to run as a standalone script for testing the functionality that is contained within the module. This is referred to as unit testing. For example, suppose you have created a module fact.py
containing a factorial function, as follows:
def fact(n):
return 1 if n == 1 else n * fact(n-1)
if (__name__ == '__main__'):
import sys
if len(sys.argv) > 1:
print(fact(int(sys.argv[1])))
You can treat the file as a module and import fact()
:
>>> from fact import fact
>>> fact(6)
720
But you can also run it as a standalone by passing an integer argument on the command-line for testing:
$ python3 fact.py 6
720
If you would like to learn more about running scripts with command line arguments check out this course on Command Line Interfaces in Python.
00:00
In this video, you’ll learn about executing a module as a script. Is a module also a Python script? Well, yeah! Any .py
file that contains a module is essentially also a Python script.
00:11
Let me have you take a look at that. If we were to open up the code for mod.py
, you can see it’s very simple. And just as a reminder, you set up a string, a list, defined a function called printy()
, and a class called Classy
.
00:24
What if you were to execute mod.py
as a script? Is it possible? Sure. As long as you’re in the same directory, type python
or python3
mod.py
, and in this case, mod.py
doesn’t output anything.
00:37 So, that’s what you should get. No errors. It apparently worked. It’s not very interesting since it’s only defining objects and then it doesn’t really do anything with them. Now, you could modify it.
00:46
You could print(s)
, print(a)
, run printy()
,
00:57
even define x
as a Classy
object and then print out x
. Okay. So I’m re-saving. It should be a little bit more interesting.
01:06
python3 mod.py
. Okay, so it printed the string, printed out the list, showed the argument for printy()
and then it shows that when this is running, the name of the module is __main__
, and Classy object
.
01:20 What does it look like when you import it now? Start the REPL.
01:26
Inside that REPL session, if you were to run import mod
, what’s going to happen? It’s going to run all that code. One note you might notice that here, it used to say __main__
, now it says mod
. And it outputs it.
01:38
Now, this is probably not what you want. You probably want when you run mod.py
for it to show the output, but when you import mod
, you may not want this output to happen.
01:49 You may want to be able to show output for testing purposes, but you may not want it to happen every time you import it. It would be much better if the output was optional.
02:00 So, there’s something to help out.
02:03 Is there something you can do if you don’t want that module to generate any output when you’re simply importing it? There is a tool that can help with this.
02:11
It uses what’s called a dunder variable. Dunder variables are variables that have double underscores (__
) before their names. In this case, the dunder variable is actually __name__
.
02:21
__name__
will automatically be set to the name of the module when it’s imported. That’s different from when a Python script, a .py
file, is run as a standalone script. In that circumstance, __name__
is set to the string '__main__'
. So, how can you use this?
02:42
I’m going to exit here, go back to mod.py
, and I’m going to change the code a little bit. Just before all of this starts, create an if
statement. And in the if
statement you’re going to use that variable, that dunder variable of __name__
.
02:57
So if __name__ == '__main__':
, which is what happens when you execute the script by itself—not importing—then go ahead and do all this activity. I’ll have you tab all this information over.
03:10
So, only if the __name__
is '__main__'
. Save. So this time,
03:18
if you were to run python3
and run mod.py
, you can see that running it by itself, the __name__
is __main__
.
03:26
And if you were to be inside your REPL, in that case, if you were to import mod
, it doesn’t, which is pretty neat! So again, going back to dir()
, you might remember that, right? So here is mod
imported, right? And you might remember this guy. I don’t know if you noticed him before, but what is the current __name__
? Well, what’s running here is this __main__
REPL session.
03:48
If you were to go inside and say, well, what is mod.__name__
? Well, mod.__name__
is 'mod'
. However, if a file is run as a standalone script, __name__
is going to be set to the string '__main__'
.
04:01
And that’s how you can use that test. Pretty neat! One reason that you may want to run the module as a standalone script is to test the contents of it, so that’s what this next example is all about. Make a new file, call it fact.py
.
04:22
And inside fact.py
, you’re going to define a pretty simple function that is a factorial, and just call it fact()
again.
04:44
You can set up the same conditional statement of if the current __name__
is equal to the string '__main__'
, then you know it’s being executed then as a standalone script.
04:57
Don’t worry too much about the nitty-gritty of the next chunk of code, but you’re importing another module, the sys
(system) module, and you’re going to use a tool called argv
that allows you to use command line arguments.
05:11
I’ll include a link to an article that tells you a little bit more about running scripts with command line arguments below this video. To be able to do some testing, you’re going to set up another if
statement, and here it’s looking for an optional argument that you can add when you execute the code as a script—then it’s going to print the output of the fact()
function after converting this argument into an integer from a string.
05:36
Make sure you save fact.py
, and to test out if you can import fact()
,
05:42
go ahead and start a new REPL session. from fact import fact
, so fact()
is available and it takes an argument of n
. Let’s say, “What’s the factorial of 6
?” So, that shows that fact
works as a module.
05:55
Now, you could test the code inside of fact
as a standalone script also. If you were back here in the terminal and you were to simply type in python3 fact.py
and then give it an argument of 6
, that conditional if
statement is allowing you to run the code underneath it and print out the result right there in the terminal, therefore allowing a level of testing.
theramstoss on June 14, 2020
Figured it out, sorry!
Alexia on Aug. 23, 2021
Hi, I just want to make a quick note on a typo I found here:
Unfortunately, now it also generates output when imported as a module:
$ python3 mod.py
Computers are useless. They can only give you answers.
[100, 200, 300]
arg = Good Day Sir!
<__main__.Classy object at 0x10f7a35f8>
Instead of _ main _ is should be _ mod _ if I am not wrong :)
Bartosz Zaczyński RP Team on Aug. 23, 2021
@Alexia You made an interesting observation here. Both outputs are correct, but they depend on how you call the code inside your module.
Specifically, when you run the module directly through the Python interpreter, then the class will be scoped within the __main__
namespace:
$ python mod.py
<__main__.Classy object at 0x7f5ee53662b0>
Notice the __main__.Classy
name.
On the other hand, importing the module elsewhere will also execute the code, but the class will be scoped differently:
$ python -q
>>> import mod
<mod.Classy object at 0x7f83bcccedc0>
The class appears to be defined in the module’s file now. This is intended and has to do with the implicit __name__
variable, which you typically use to detect when a file is imported vs. executed as a script.
Hence, the if __name__ == "__main__"
idiom in Python.
Alexia on Sept. 2, 2021
Yes sorry I didn’t explained exactly what I meant. I don’t know how to add a screenshot in this comment but I will try to explain it better.
Under the Desciption of this video, after we created the python file:
s = "Computers are useless. They can only give you answers."
a = [100, 200, 300]
def printy(arg):
print(f'arg = {arg}')
class Classy:
pass
print(s)
print(a)
printy('Good Day Sir!')
x = Classy()
print(x)
First we run python3 mod.py
from Python interpreter and the scope of the class is <__main__.Classy object at 0x10f7a35f8>
.
Then we import the module. In this output the class seems again to be scoped <__main__.Classy object at 0x111324748>
.
So in both outputs it is __main__
.
ori yungrais on Sept. 20, 2023
Hi, “05:11 I’ll include a link to an article that tells you a little bit more about running scripts with command line arguments below this video.”
Is there a link?
Chris Bailey RP Team on Sept. 20, 2023
Hi @ori yungrais,
There is a course Command Line Interfaces in Python – Real Python and it’s companion written tutorial Python Command-Line Arguments. It’s also now at the bottom of the description text for this lesson. Thanks!
Become a Member to join the conversation.
theramstoss on June 14, 2020
How do you set it up so that you don’t have to import sys and append the path every time? Thanks.