1

I am using two test scripts to teach myself how to use argparse and subprocess libraries in Python. I am confused about the type=int value in add_argument().

calculator.py:

import sys
x = int(sys.argv[1])
y = int(sys.argv[2])
print(x,y)
print(x+y)

wrapper.py:

from subprocess import run
import argparse
import sys
parser = argparse.ArgumentParser(description='Wrapper.')
parser.add_argument('-x', nargs=1, type=int, dest='x', default=0, help='x.', required=True)
parser.add_argument('-y', nargs=1, type=int, dest='y', default=0, help='y.', required=True)
args = parser.parse_args()
if len(sys.argv) == 1:
    parser.print_help()
else:
    print('args.x and args.y')
    run(["python","calculator.py", str(args.x), str(args.y)])
    print('args.x[0] and args.y[0]')
    run(["python","calculator.py", str(args.x[0]), str(args.y[0])])

Output:

args.x and args.y
[1] [8]
[1][8]
args.x[0] and args.y[0]
1 8
9

To me the above is unexpected behaviour. I want the values of args.x and args.y to be ints, but they are lists with a single entry. Can someone explain why this is and possibly how to change my add_argument lines to store ints and/or demonstrate proper usage of argparse?

This question:Python argparse: default argument stored as string, not list was flagged as similar. Although the solution is the same, the question is not - there the question was about the default value not being a list, here the stored value is a list. In that question the title does not ask the same question as the body, therefore I did not realise I could use the answer to that question. I have submitted an answer to that question elaborating on this point.

Dave
  • 312
  • 3
  • 11
  • 1
    [`nargs`](https://docs.python.org/3/library/argparse.html#nargs) always means a list: *"Note that `nargs=1` produces a list of one item. This is different from the default, in which the item is produced by itself."* If you want just a single value, don't set it. If you did want a list of integers, you could use e.g. `type=lambda l: [int(i) for i in l]`. – jonrsharpe Jan 22 '21 at 11:31
  • 1
    @jonrsharpe, not need for the `lambda`. The `type` function is applied individually to each string, even if `nargs` is 2 or '*'. And to be picky, we can specify `nargs=None` and get the default behavior. – hpaulj Jan 23 '21 at 00:18
  • @hpaulj ah that makes sense, neat – jonrsharpe Jan 23 '21 at 07:47

1 Answers1

3

Remove the nargs=1 part.
From: https://docs.python.org/3/library/argparse.html#nargs

Note that nargs=1 produces a list of one item. This is different from the default, in which the item is produced by itself.

  • ok, but if I remove `nargs=1`, how do I then ensure that the option takes one argument? – 400 the Cat Feb 01 '21 at 05:54
  • If `nargs` is not specified only a single argument can be given. For example if I specify `parser.add_argument('--test',dest='test')` in my wrapper.py, then run `python wrapper.py --test 1 2`, this causes argparse to print the usage, followed by the line `wrapper.py: error: unrecognized arguments: 2` – Dave Feb 01 '21 at 13:39
  • From the link in this answer: "ArgumentParser objects usually associate a single command-line argument with a single action to be taken. The nargs keyword argument associates a different number of command-line arguments with a single action." – Dave Feb 01 '21 at 13:45