Allow optional before required arguments

I recently discovered you can do this in argparse:

import argparse

parser = argparse.ArgumentParser()
parser.add_argument("a", nargs="?", default=0)
parser.add_argument("b")
parser.add_argument("c", nargs="?", default=0)
parser.add_argument("d")
parser.add_argument("args", nargs="*")
args = parser.parse_args()
print(args.a, args.b, args.c, args.d, *args.args)
$ python test.py
usage: test.py [-h] [a] b [c] d [args ...]
test.py: error: the following arguments are required: b, d, args
$ python test.py 1 2
0 1 0 2
$ python test.py 1 2 3
1 2 0 3
$ python test.py 1 2 3 4
1 2 3 4
$ python test.py 1 2 3 4 5
1 2 3 4 5

Wouldn’t it make a lot of sense to support this in Python as well? This is concise and supports kwargs. e.g.

def range_wrapper(start=1, stop, step=1):
    return range(start, stop + 1, step)
>>> [*range_wrapper(5)]
[1, 2, 3, 4, 5]
>>> [*range_wrapper(-1, 1)]
[-1, 0, 1]
>>> [*range_wrapper(-4, 4, 2)]
[-4, -2, 0, 2, 4]
>>> [*range_wrapper(stop=5)]
[1, 2, 3, 4, 5]
>>> [*range_wrapper(start=-1, stop=1)]
[-1, 0, 1]
>>> [*range_wrapper(start=-4, stop=4, step=2)]
[-4, -2, 0, 2, 4]

Range could then be defined in the stubs as follows:

class range:
    def __new__(cls, start: int = 0, stop: int, step: int = 1, /) -> Self:
        ...

A more thought out suggestion for this has been done before: Defaults anywhere in positional-only parameters

I would suggest you read through it and try to answer all objections.

And in general: please do a bit of research before posting new threads here, rehashing the same discussions again and again is a waste of everyone’s time.

2 Likes

Thanks for finding that, I looked for parameter without a default follows parameter with a default, but couldn’t find that discussion. I’ll read through it.

I’ll note that no one mentioned argparse in that thread, which can be used for testing purposes and even supports *args. Sadly it only works for positional only arguments.