71

I was trying to pass two lists containing integers as arguments to a python code. But sys.argv[i] gets the parameters as a list of string.

Input would look like,

$ python filename.py [2,3,4,5] [1,2,3,4]

I found the following hack to convert the list.

strA = sys.argv[1].replace('[', ' ').replace(']', ' ').replace(',', ' ').split()
strB = sys.argv[2].replace('[', ' ').replace(']', ' ').replace(',', ' ').split()
A = [float(i) for i in strA]
B = [float (i) for i in strB]

Is there a better way to do this?

2
  • 1
    You can look into serialization techniques; this is what I usually do when I have to pass list-like structures as parameters via the command line. You could also look into JSON or other forms of data serialization. (But before you get too far into a solution, I'd make sure passing lists as parameters on the command line truly is what you need, and that this isn't an X-Y problem) Commented Sep 24, 2015 at 13:03
  • Why not lists = [[int(el) for el in arg[1:-1].split(',')] for arg in sys.argv[1:]]? Here you can see that the brackets are rather useless in this case. Commented May 28, 2019 at 10:34

9 Answers 9

144

Don't reinvent the wheel. Use the argparse module, be explicit and pass in actual lists of parameters

import argparse
# defined command line options
# this also generates --help and error handling
CLI=argparse.ArgumentParser()
CLI.add_argument(
  "--lista",  # name on the CLI - drop the `--` for positional/required parameters
  nargs="*",  # 0 or more values expected => creates a list
  type=int,
  default=[1, 2, 3],  # default if nothing is provided
)
CLI.add_argument(
  "--listb",
  nargs="*",
  type=float,  # any type/callable can be used here
  default=[],
)

# parse the command line
args = CLI.parse_args()
# access CLI options
print("lista: %r" % args.lista)
print("listb: %r" % args.listb)

You can then call it using

$ python my_app.py --listb 5 6 7 8 --lista  1 2 3 4
lista: [1, 2, 3, 4]
listb: [5.0, 6.0, 7.0, 8.0]
3
  • 1
    This is the best answer out there. Just use nargs of argparse.
    – Qinsi
    Commented May 29, 2019 at 8:26
  • 3
    @MisterMiyagi wax on wax off Commented Sep 13, 2019 at 9:39
  • This one is the better coding practice. Thanks Commented Dec 23, 2019 at 8:16
26

Command line arguments are always passed as strings. You will need to parse them into your required data type yourself.

>>> input = "[2,3,4,5]"
>>> map(float, input.strip('[]').split(','))
[2.0, 3.0, 4.0, 5.0]
>>> A = map(float, input.strip('[]').split(','))
>>> print(A, type(A))
([2.0, 3.0, 4.0, 5.0], <type 'list'>)

There are libraries like argparse and click that let you define your own argument type conversion but argparse treats "[2,3,4]" the same as [ 2 , 3 , 4 ] so I doubt it will be useful.

edit Jan 2019 This answer seems to get a bit of action still so I'll add another option taken directly from the argparse docs.

You can use action=append to allow repeated arguments to be collected into a single list.

>>> parser = argparse.ArgumentParser()
>>> parser.add_argument('--foo', action='append')
>>> parser.parse_args('--foo 1 --foo 2'.split())
Namespace(foo=['1', '2'])

In this case you would pass --foo ? once for each list item. Using OPs example: python filename.py --foo 2 --foo 3 --foo 4 --foo 5 would result in foo=[2,3,4,5]

4
  • 1
    print(A) gives out a <map object>.
    – kev
    Commented Mar 11, 2019 at 18:40
  • convert A to list like: A = list(map(int, input.strip('[]').split(','))) print(A, type(A)) Commented Apr 13, 2020 at 19:07
  • I originally wrote this in 2015 using python2 in which map is returning a list. Python 3 does indeed return a map (iterator)
    – Josh J
    Commented Jun 4, 2020 at 14:58
  • 1
    So please add this Info to your original answer for prominent clarification.
    – Fred
    Commented Jan 22, 2021 at 8:31
23

I tested this on my end, and my input looks like this:

python foo.py "[1,2,3,4]" "[5,6,7,8,9]"

I'm doing the following to convert the two params of interest:

import ast
import sys

list1 = ast.literal_eval(sys.argv[1])
list2 = ast.literal_eval(sys.argv[2])
1
  • 4
    throws ValueError: malformed node or string: <_ast.Name object at 0x0000024929290518>, my argument is "[n01530575,n01530576]"
    – user924
    Commented Apr 12, 2019 at 8:24
16

Why not:

python foo.py 1,2,3,4 5,6,7,8  

Much cleaner than trying to eval python and doesn't require your user to know python format.

import sys

list1 = sys.argv[1].split(',')
list2 = [int(c) for c in sys.argv[2].split(',')]  # if you want ints
11

You can also do the following:

say, you have foo.py :

import json
import sys
data = json.loads(sys.argv[1])
print data, type(data)

Then if you run the above as : python foo.py "[1,2,3]"

Output:

[1, 2, 3] <type 'list'>

2
  • 3
    it thorws json.decoder.JSONDecodeError: Expecting value: line 1 column 2 (char 1)
    – user924
    Commented Apr 12, 2019 at 8:22
  • 1
    p.s. my argument is "[n01530575,n01530576]"
    – user924
    Commented Apr 12, 2019 at 8:23
8

You can simply use nargs='+' option of argparse

import argparse
parser = argparse.ArgumentParser()
parser.add_argument('--myarg', dest='myarg', required=False, help='--myarg 100 100 100 takes a list of 3 elements, each is of value 100 ', nargs='+', type=int, default=[100,100,100])

You can then pass arguments like this:

python your_file.py --myarg 1 2 3

This will be stored in your program in myarg as [1,2,3]

print(myarg)

Outputs:

[1,2,3]
5

No, there is no way pass a list in a command line argument. Command line arguments are always string. But there is a better way to convert it to list. You can do it like that:

import ast

A = ast.literal_eval(strA)
B = ast.literal_eval(strB)
3

You have to escape:

python some.py \[2,3,4,5\] \[1,2,3,4\]

some.py

import sys

print sys.argv[1]
print sys.argv[2]

this gives me:

[2,3,4,5]
[1,2,3,4]

Bash out

UPDATE:

import sys
import ast

d = ast.literal_eval(sys.argv[1])
b = ast.literal_eval(sys.argv[2])

for a in d:
    print a

for e in b:
    print e

first will give:

2
3
4
5

and second will give

1
2
3
4
3
  • what happens when you print the type of what you did there?
    – postelrich
    Commented Sep 24, 2015 at 13:23
  • That still gives a string when you output the type
    – idjaw
    Commented Sep 24, 2015 at 13:23
  • i have updated answer. but i see now it is same as stackoverflow.com/a/32762516/1108279
    – pregmatch
    Commented Sep 24, 2015 at 13:35
0

You could also use this way:

Suppose you are trying to pass a list of numbers to Python code:

python3 check.py --ids 25,36

Inside the code, you just need to read ids as follows:

list(eval(args.ids))

Then you will see:

[25,36]

Not the answer you're looking for? Browse other questions tagged or ask your own question.