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 Comment
3 comments, sorted by Click to highlight new comments since: Today at 8:35 PM

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.

New to LessWrong?