Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it bad practice to have arguments called in main() in Python

Tags:

python

main

Should the function name main() always be empty and have arguments called within the function itself or is it acceptable to have them as inputs to the function e.g main(arg1, arg2, arg3)?

I know it works but I'm wondering if it is poor programming practice. Apologies if this is a duplicate but I couldn't see the question specifically answered for Python.

like image 229
Capeboom Avatar asked Nov 08 '18 09:11

Capeboom


People also ask

Should a main function have arguments Python?

Many programming languages have a special function that is automatically executed when an operating system starts to run a program. This function is usually called main() and must have a specific return type and arguments according to the language standard.

Can we pass arguments in main ()?

Yes, we can give arguments in the main() function. Command line arguments in C are specified after the name of the program in the system's command line, and these argument values are passed on to your program during program execution. The argc and argv are the two arguments that can pass to main function.

Is it good practice to have a main function in Python?

The main function is mandatory in programs like C, Java, etc, but it is not necessary for python to use the main function, however it is a good practice to use it. If your program has if __name__ == “__main__” statement then the program is executed as a standalone program.

How do you pass arguments to mains in Python?

Command Line Args Python Code The main() above begins with a CS106A standard line args = sys. argv[1:] which sets up a list named args to contain the command line arg strings. This line works and you can always use it.


2 Answers

By following the pattern:

def main():
    ...stuff...

if __name__ == '__main__':
    main()

It allows your script to both to be run directly, and if packaged using setup tools, to have an executable script generated automatically when the package is installed by specifying main as an entry point.

See: https://setuptools.readthedocs.io/en/latest/setuptools.html#automatic-script-creation

You would add to setup.py something like:

entry_points={
    'console_scripts': [
        'my_script = my_module:main'
    ]
}

And then when you build a package, people can install it in their virtual environment, and immediately get a script called my_script on their path.

Automatic script creation like this requires a function that takes no required arguments.

It's a good idea to allow you script to be imported and expose it's functionality both for code reuse, and also for testing. I would recommend something line this pattern:

import argparse

def parse_args():
    parser = argparse.ArgumentParser()
    #
    # ... configure command line arguments ...
    #
    return parser.parse_args()

def do_stuff(args):
    #
    # ... main functionality goes in here ...
    #

def main():
    args = parse_args()
    do_stuff(args)

if __name__ == '__main__':
    main()

This allows you to run your script directly, have an automatically generated script that behaves the same way, and also import the script and call do_stuff to re-use or test the actual functionality.

This blog post was mentioned in the comments: https://www.artima.com/weblogs/viewpost.jsp?thread=4829 which uses a default argument on main to allow dependency injection for testing, however, this is a very old blog post; the getopt library has been superseded twice since then. This pattern is superior and still allows dependency injection.

like image 57
SpoonMeiser Avatar answered Sep 29 '22 17:09

SpoonMeiser


In most other programming languages, you'd either have zero parameters or two parameters:

int main(char *argv[], int argc)

To denote the arguments passed through to the parameter. However, in Python these are accessed through the sys module:

import sys

def main():
    print(sys.argv, len(sys.argv))

But then you could extend this so that you pass through argv and argc into your python function, similar to other languages yes:

import sys

def main(argv, arc):
    print(argv, arc)

if __name__ == '__main__':
    main(sys.argv, len(sys.argv))

But let's forget about argv/argc for now - why would you want to pass something through to main. You create something outside of main and want to pass it through to main. And this can happen in two instances:

  1. You're calling main multiple times from other functions.
  2. You've created variables outside main that you want to pass through.

Point number 1 is definitely bad practice. main should be unique and called only once at the beginning of your program. If you have the need to call it multiple times, then the code inside main doesn't belong inside main. Split it up.

Point number 2 may seem like it makes sense, but then you do it in practise:

def main(a, b):
    print(a, b)

if __name__ == '__main__':
    x = 4
    y = 5
    main(x, y)

But then aren't x and y global variables? And good practice would assume that these are at the top of your file (and multiple other properties - they're constant, etc), and that you wouldn't need to pass these through as arguments.

like image 26
TerryA Avatar answered Sep 29 '22 17:09

TerryA