When Should You Use the Name-Main Idiom?
00:00 Now that you know about what the name-main idiom does and how it works, does that mean you should add it to all of your scripts? Well, not necessarily. But first, let’s look at when you would want to use the name-main idiom.
00:14 Generally speaking, you want to use the name-main idiom when you have a file that’s going to be run as both a stand-alone script and an importable module, but you also have to have some code that you don’t want to run when it’s being imported. Said another way, you want to avoid producing side effects when importing. In practice, the most common times when you need to actually use the name-main idiom are if you have a module that contains some useful functionality, and you want to create an entry point to it from the command line, or if you have a script, and then you want to write tests for it that would involve importing some content into a separate test file while not running the script’s main functionality.
01:00
So, when building a command-line entry point, it usually involves accepting user input in some way to alter how it’s being run. As an example, think about the built-in math
module.
01:11 It’s a collection of useful math functions, and if you wanted to access some of its functionality directly from the command line, you could use the name-main idiom to collect some user input to control what you want to run, and then call the appropriate functions based on the input you’ve received.
01:30
So looking at the ways in which you can collect user input, you already have seen the input()
function, which prompts a user for input into the console, but you can also provide inputs directly into the command line. When you’re running your script, after the filename, you can add multiple arguments separated by spaces. In this example, there are two arguments, HELLO
and WORLD
, and those would be passed into repeat.py
.
02:00
Note that if you tried running this command with our current repeat.py
, it would ignore those arguments. But in a moment, you’ll see how to update repeat.py
to access those arguments first through the argv
variable from the built-in sys
module.
02:17
These arguments will be used to get the text to repeat from the user, and instead of doing it through the input()
function. In addition to sys.argv
, if you needed to accept more complicated arguments, you could instead use a dedicated command-line interface library to handle more complex inputs. You’re not going to see an example of that in this course, but I will provide some additional resources for you to learn more about creating command-line interfaces at the end of the course.
02:49
Here’s an example of how to use the sys
module to handle script arguments. You have the base repeat.py
file here, and at the top of the file, you can add import sys
.
03:06
Then on the line that is accepting the text through user input, instead of calling the input()
function, you can access sys.argv
, where argv
is a variable that contains a list of arguments passed into the script. And all of those arguments are going to be strings.
03:29 Then the first argument is always going to be the filename. So, we actually want to ignore that one. You can get the argument from one onwards to get all of the ones that are passed into the script. Then,
03:48
you can join all of those together with spaces in between by calling the .join()
method on a string that includes the space character (" "
), and that will take all of the arguments passed into your script and combine them into one single line of text with spaces.
04:10
So to use it, you can run python repeat.py
HELLO WORLD
, and now it uses the input passed into the script, and it doesn’t prompt you for any text.
04:26
So imagine you originally had the repeat()
function, and that’s being imported by other scripts. Now, by using the name-main idiom here, you’ve got an entry point to the function through the command line and a dedicated place to work with user inputs that won’t affect any other scripts.
04:48 And that was a quick primer on how to add a command-line entry point to your module. Now let’s quickly look at writing tests for your script.
04:57
Here’s a new file called test.py
that shows how to test your repeat()
function using the unittest
framework that comes included in the Python standard library. In the first line, you’re importing the unittest
package, and on the next line, you’re importing the repeat
function from the repeat
module.
05:15
Note that this line will only work as is if test.py
and repeat.py
are in the same folder. This is also the line that will execute the repeat.py
file because it’s being imported as a module. Remember, in repeat.py
, you’re using the name-main idiom and only asking the user for input or accepting arguments when the file is run as a script.
05:44
So that way, if you’re importing it like here in the test, you’re not actually going to run that additional functionality, and you can just import the function on its own. So, so after the import statement, you are creating a new class, which is a test case, and it has one method that checks if the default number of repetitions for the repeat()
function is equal to two.
06:12
And then at the end, it’s also using the name-main idiom, and it’s running the test suite when this file is called directly as a script, and you can see how it runs. If you do python test.py
, it says it ran one test, and everything was correct and successful.
06:37 And if you want to see the outcome with a test that fails,
06:43 it would look like this and show you what the difference was between what was expected and what the actual outcome was.
06:55 As an overview of use cases for the name-main idiom, the primary ones are if you want to add a command-line entry point to a module or if you want to write tests for a script.
07:09 In the next lesson, you’ll learn about some use cases that you might be tempted to use the name-main idiom for, but when another solution might be better.
Bartosz Zaczyński RP Team on Aug. 9, 2023
@Dick de Goede Does your tests.py
file include the following line at the bottom?
if __name__ == "__main__":
unittest.main()
Without it, Python will read your unit tests but won’t execute them.
Become a Member to join the conversation.
Dick de Goede on Aug. 9, 2023
Hello, when I try to run the unittest I get no output. However when I run the test like this I do get the correct output:
py -m unittest tests.py
I do have the repeat.py and tests.py exactly as they should be. Obviously here I force using the unittest module when running the statement. Do you have any idea why I do no not get any output when running it like
py tests.py
?Hope to hear from you soon, thank you :)