79

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

153

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]
Sign up to request clarification or add additional context in comments.

2 Comments

This is the best answer out there. Just use nargs of argparse.
@MisterMiyagi wax on wax off
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 Comments

print(A) gives out a <map object>.
convert A to list like: A = list(map(int, input.strip('[]').split(','))) print(A, type(A))
I originally wrote this in 2015 using python2 in which map is returning a list. Python 3 does indeed return a map (iterator)
So please add this Info to your original answer for prominent clarification.
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 Comment

throws ValueError: malformed node or string: <_ast.Name object at 0x0000024929290518>, my argument is "[n01530575,n01530576]"
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

Comments

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 Comments

it thorws json.decoder.JSONDecodeError: Expecting value: line 1 column 2 (char 1)
p.s. my argument is "[n01530575,n01530576]"
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]

Comments

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)

Comments

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 Comments

what happens when you print the type of what you did there?
That still gives a string when you output the type
i have updated answer. but i see now it is same as stackoverflow.com/a/32762516/1108279
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]

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.