function_that_needs_strings(*my_list) # works!
You can read all about it here: Unpacking Argument Lists - The Python Tutorial
Answer from Jochen Ritzel on Stack Overflowfunction_that_needs_strings(*my_list) # works!
You can read all about it here: Unpacking Argument Lists - The Python Tutorial
Yes, you can use the *args (splat) syntax:
function_that_needs_strings(*my_list)
where my_list can be any iterable; Python will loop over the given object and use each element as a separate argument to the function.
See the call expression documentation.
There is a keyword-parameter equivalent as well, using two stars:
kwargs = {'foo': 'bar', 'spam': 'ham'}
f(**kwargs)
and there is equivalent syntax for specifying catch-all arguments in a function signature:
def func(*args, **kw):
# args now holds positional arguments, kw keyword arguments
Passing an array/list into a Python function - Stack Overflow
python - Converting list to *args when calling function - Stack Overflow
python - How can I pass a list as a command-line argument with argparse? - Stack Overflow
How to pass a list as argument to map?
Videos
When you define your function using this syntax:
def someFunc(*args):
for x in args
print x
You're telling it that you expect a variable number of arguments. If you want to pass in a List (Array from other languages) you'd do something like this:
def someFunc(myList = [], *args):
for x in myList:
print x
Then you can call it with this:
items = [1,2,3,4,5]
someFunc(items)
You need to define named arguments before variable arguments, and variable arguments before keyword arguments. You can also have this:
def someFunc(arg1, arg2, arg3, *args, **kwargs):
for x in args
print x
Which requires at least three arguments, and supports variable numbers of other arguments and keyword arguments.
You can pass lists just like other types:
l = [1,2,3]
def stuff(a):
for x in a:
print a
stuff(l)
This prints the list l. Keep in mind lists are passed as references not as a deep copy.
You can use the * operator before an iterable to expand it within the function call. For example:
timeseries_list = [timeseries1 timeseries2 ...]
r = scikits.timeseries.lib.reportlib.Report(*timeseries_list)
(notice the * before timeseries_list)
From the python documentation:
If the syntax *expression appears in the function call, expression must evaluate to an iterable. Elements from this iterable are treated as if they were additional positional arguments; if there are positional arguments x1, ..., xN, and expression evaluates to a sequence y1, ..., yM, this is equivalent to a call with M+N positional arguments x1, ..., xN, y1, ..., yM.
This is also covered in the python tutorial, in a section titled Unpacking argument lists, where it also shows how to do a similar thing with dictionaries for keyword arguments with the ** operator.
yes, using *arg passing args to a function will make python unpack the values in arg and pass it to the function.
so:
>>> def printer(*args):
print args
>>> printer(2,3,4)
(2, 3, 4)
>>> printer(*range(2, 5))
(2, 3, 4)
>>> printer(range(2, 5))
([2, 3, 4],)
>>>
SHORT ANSWER
Use the nargs option or the 'append' setting of the action option (depending on how you want the user interface to behave).
nargs
parser.add_argument('-l','--list', nargs='+', help='<Required> Set flag', required=True)
# Use like:
# python arg.py -l 1234 2345 3456 4567
nargs='+' takes 1 or more arguments, nargs='*' takes zero or more.
append
parser.add_argument('-l','--list', action='append', help='<Required> Set flag', required=True)
# Use like:
# python arg.py -l 1234 -l 2345 -l 3456 -l 4567
With append you provide the option multiple times to build up the list.
Don't use type=list!!! - There is probably no situation where you would want to use type=list with argparse. Ever.
LONG ANSWER
Let's take a look in more detail at some of the different ways one might try to do this, and the end result.
import argparse
parser = argparse.ArgumentParser()
# By default it will fail with multiple arguments.
parser.add_argument('--default')
# Telling the type to be a list will also fail for multiple arguments,
# but give incorrect results for a single argument.
parser.add_argument('--list-type', type=list)
# This will allow you to provide multiple arguments, but you will get
# a list of lists which is not desired.
parser.add_argument('--list-type-nargs', type=list, nargs='+')
# This is the correct way to handle accepting multiple arguments.
# '+' == 1 or more.
# '*' == 0 or more.
# '?' == 0 or 1.
# An int is an explicit number of arguments to accept.
parser.add_argument('--nargs', nargs='+')
# To make the input integers
parser.add_argument('--nargs-int-type', nargs='+', type=int)
# An alternate way to accept multiple inputs, but you must
# provide the flag once per input. Of course, you can use
# type=int here if you want.
parser.add_argument('--append-action', action='append')
# To show the results of the given option to screen.
for _, value in parser.parse_args()._get_kwargs():
if value is not None:
print(value)
Here is the output you can expect:
$ python arg.py --default 1234 2345 3456 4567
...
arg.py: error: unrecognized arguments: 2345 3456 4567
$ python arg.py --list-type 1234 2345 3456 4567
...
arg.py: error: unrecognized arguments: 2345 3456 4567
$ # Quotes won't help here...
$ python arg.py --list-type "1234 2345 3456 4567"
['1', '2', '3', '4', ' ', '2', '3', '4', '5', ' ', '3', '4', '5', '6', ' ', '4', '5', '6', '7']
$ python arg.py --list-type-nargs 1234 2345 3456 4567
[['1', '2', '3', '4'], ['2', '3', '4', '5'], ['3', '4', '5', '6'], ['4', '5', '6', '7']]
$ python arg.py --nargs 1234 2345 3456 4567
['1234', '2345', '3456', '4567']
$ python arg.py --nargs-int-type 1234 2345 3456 4567
[1234, 2345, 3456, 4567]
$ # Negative numbers are handled perfectly fine out of the box.
$ python arg.py --nargs-int-type -1234 2345 -3456 4567
[-1234, 2345, -3456, 4567]
$ python arg.py --append-action 1234 --append-action 2345 --append-action 3456 --append-action 4567
['1234', '2345', '3456', '4567']
Takeaways:
- Use
nargsoraction='append'nargscan be more straightforward from a user perspective, but it can be unintuitive if there are positional arguments becauseargparsecan't tell what should be a positional argument and what belongs to thenargs; if you have positional arguments thenaction='append'may end up being a better choice.- The above is only true if
nargsis given'*','+', or'?'. If you provide an integer number (such as4) then there will be no problem mixing options withnargsand positional arguments becauseargparsewill know exactly how many values to expect for the option.
- Don't use quotes on the command line1
- Don't use
type=list, as it will return a list of lists- This happens because under the hood
argparseuses the value oftypeto coerce each individual given argument you your chosentype, not the aggregate of all arguments. - You can use
type=int(or whatever) to get a list of ints (or whatever)
- This happens because under the hood
1: I don't mean in general.. I mean using quotes to pass a list to argparse is not what you want.
I prefer passing a delimited string which I parse later in the script. The reasons for this are; the list can be of any type int or str, and sometimes using nargs I run into problems if there are multiple optional arguments and positional arguments.
parser = ArgumentParser()
parser.add_argument('-l', '--list', help='delimited list input', type=str)
args = parser.parse_args()
my_list = [int(item) for item in args.list.split(',')]
Then,
python test.py -l "265340,268738,270774,270817" [other arguments]
or,
python test.py -l 265340,268738,270774,270817 [other arguments]
will work fine. The delimiter can be a space, too, which would though enforce quotes around the argument value like in the example in the question.
Or you can use a lambda type as suggested in the comments by Chepner:
parser.add_argument('-l', '--list', help='delimited list input',
type=lambda s: [int(item) for item in s.split(',')])
plants escape snatch angle bedroom liquid oatmeal library flag touch
This post was mass deleted and anonymized with Redact
test function:
You can use multiple arguments represented by *args and multiple keywords represented by **kwargs and passing to a function:
def test(*args, **kwargs):
print('arguments are:')
for i in args:
print(i)
print('\nkeywords are:')
for j in kwargs:
print(j)
Example:
Then use any type of data as arguments and as many parameters as keywords for the function. The function will automatically detect them and separate them to arguments and keywords:
a1 = "Bob" #string
a2 = [1,2,3] #list
a3 = {'a': 222, #dictionary
'b': 333,
'c': 444}
test(a1, a2, a3, param1=True, param2=12, param3=None)
Output:
arguments are:
Bob
[1, 2, 3]
{'a': 222, 'c': 444, 'b': 333}
keywords are:
param3
param2
param1
You can change it to:
def WorkDetails(link, details):
Then invoke it as:
details = [ AllcurrValFound_bse, AllyearlyHLFound_bse,
AlldaysHLFound_bse, AllvolumeFound_bse,
AllprevCloseFound_bse, AllchangePercentFound_bse,
AllmarketCapFound_bse ]
workDetails(link, details)
And you would get the different values out of details by:
AllcurrValFound_bse = details[0]
AllyearlyHLFound_bse = details[1]
...
It would be more robust to turn details into a dictionary, with the variable names as keys, so take your pick between a few more lines of code vs. defensive programming =p