I'll illustrate the normal behavior of default in argparse (with a Ipython interactive session)
In [32]: parser = argparse.ArgumentParser()
Define 3 Actions:
In [33]: parser.add_argument('-r', nargs=3, type=int, default=(1,2,3));
In [35]: parser.add_argument('-f', default='DEFAULT');
In [37]: parser.add_argument('-g', nargs='?', default='DEFAULT', const='const');
The help. Note that all Actions have [], indicating that they are optional:
In [39]: parser.print_help()
usage: ipython3 [-h] [-r R R R] [-f F] [-g [G]]
optional arguments:
-h, --help show this help message and exit
-r R R R
-f F
-g [G]
If called without any argments, all of the defaults appear in the args namespace.
In [40]: parser.parse_args([]) # e.g python myprog.py
Out[40]: Namespace(f='DEFAULT', g='DEFAULT', r=(1, 2, 3))
Giving -r with 3 numbers (as specified by the nargs)
In [41]: parser.parse_args('-r 4 5 6'.split())
Out[41]: Namespace(f='DEFAULT', g='DEFAULT', r=[4, 5, 6])
Specify one of the other flags. Note the remaining defaults
In [42]: parser.parse_args('-f other'.split())
Out[42]: Namespace(f='other', g='DEFAULT', r=(1, 2, 3))
-g with nargs='?' has another option. It can be given without arguments. In that case it gets the const value.
In [43]: parser.parse_args('-f other -g'.split())
Out[43]: Namespace(f='other', g='const', r=(1, 2, 3))
In [44]: parser.parse_args('-f other -g more'.split())
Out[44]: Namespace(f='other', g='more', r=(1, 2, 3))
There isn't such a 3 way option for nargs=3. You either provide the 3 values, or you don't use -r. If you need to distinguish between 1) no-r flag, 2) r flag without arguments, and 3) r flat with 3 arguments, I'd suggest splitting functionality into 2 actions, one a 'store_true', and other that takes the 3 values.
Defaults in argparse can be a complicated matter, with various ways of setting them, differences between string and non-string values, even a way of suppressing them. But I've shown the basic behavior.