When I'm writing real Python programs I use argparse. When I'm writing quick scripts, I destructure sys.argv[1:]. For example:

width, depth, height = sys.argv[1:]
...

Or, if I need to import the file:

def start(width, depth, height):
  ...

if __name__ == '__main__':
  start(*sys.argv[1:])

This is a very simple way of handling positional arguments. It ignores sys.argv[0] which is likely the name of the script, and then assigns the remaining arguments to the variables. If I provide the wrong number of arguments it's a bit shouty, but it's clear enough for a quick script and does remind me of the intended arguments:

Traceback (most recent call last):
  File "example.py", line 2, in 
    width, depth, height = sys.argv[1:]
ValueError: too many values to unpack (expected 3)

Comment via: facebook

New to LessWrong?

New Comment
3 comments, sorted by Click to highlight new comments since: Today at 4:11 AM

I'd argue that using argh is just as easy and strictly better:


$ cat test.py
#!/usr/local/bin/python
import argh

def start(width, depth, height):
   print(float(width) * float(depth) * float(height))
   
if __name__ == '__main__':
   p = argh.ArghParser()
   p.set_default_command(start)
   p.dispatch()

$ ./test.py -h
usage: test.py [-h] width depth height

positional arguments:
 width       -
 depth       -
 height      -

options:
 -h, --help  show this help message and exit

$ ./test.py 1 2 3
6.0

$ ./test.py 1 2 3 4
usage: test.py [-h] width depth height
test.py: error: unrecognized arguments: 4

$ ./test.py 1 2 
usage: test.py [-h] width depth height
test.py: error: the following arguments are required: height

And it's even easier if you are willing to use commands (which is often useful when you want to extend the script to do more than one thing):

$ cat test.py
#!/usr/local/bin/python
import argh

def volume(width, depth, height):
   print(float(width) * float(depth) * float(height))

def area(width, height):
   print(float(width) * float(height))
   
if __name__ == '__main__':
   argh.dispatch_commands([volume, area])
   
$ ./test.py -h
usage: test.py [-h] {volume,area} ...

positional arguments:
  {volume,area}
    volume
    area

options:
  -h, --help     show this help message and exit

$ ./test.py volume -h
usage: test.py volume [-h] width depth height

positional arguments:
  width       -
  depth       -
  height      -

options:
  -h, --help  show this help message and exit

$ ./test.py volume 1 2 3
6.0

$ ./test.py area 12 24
288.0

Another reason this is not strictly better, is that for someone reading the source code it's likely less clear what's going on.

(But I could imagine I find the module useful at some point.)

strictly better

argh isn't in the standard library. For a quick script this matters much less than if you're building something that would stick around but it's still a downside. It's also a bit of boilerplate I'd need to look up every time to get started on a script.

In this case the benefit is minimal: slightly better error messages. The better path for improving the script is mildly helpful, but switching once you need something other than mandatory positional arguments is not hard.