What is the right way to treat Python argparse.Namespace() as a dictionary?
You can access the namespace's dictionary with vars():
>>> import argparse
>>> args = argparse.Namespace()
>>> args.foo = 1
>>> args.bar = [1,2,3]
>>> d = vars(args)
>>> d
{'foo': 1, 'bar': [1, 2, 3]}
You can modify the dictionary directly if you wish:
>>> d['baz'] = 'store me'
>>> args.baz
'store me'
Yes, it is okay to access the __dict__ attribute. It is a well-defined, tested, and guaranteed behavior.
Convert argparse Namespace to dict recursively
I don't think there's an already-made recursive solution, but here's a simple one:
def namespace_to_dict(namespace):
return {
k: namespace_to_dict(v) if isinstance(v, argparse.Namespace) else v
for k, v in vars(namespace).items()
}
>>> namespace_to_dict(args)
{'foo': 1, 'bar': [1, 2, 3], 'c': {'foo': 'a'}}
Python argparse dict arg
Here's another solution using a custom action, if you want to specify dict key pairs together comma-separated --
import argparse
import sys
parser = argparse.ArgumentParser(description='parse key pairs into a dictionary')
class StoreDictKeyPair(argparse.Action):
def __call__(self, parser, namespace, values, option_string=None):
my_dict = {}
for kv in values.split(","):
k,v = kv.split("=")
my_dict[k] = v
setattr(namespace, self.dest, my_dict)
parser.add_argument("--key_pairs", dest="my_dict", action=StoreDictKeyPair, metavar="KEY1=VAL1,KEY2=VAL2...")
args = parser.parse_args(sys.argv[1:])
print args
Running:
python parse_kv.py --key_pairs 1=2,a=bbb,c=4 --key_pairs test=7,foo=bar
Output:
Namespace(my_dict={'1': '2', 'a': 'bbb', 'c': '4', 'test': '7', 'foo': 'bar'})
If you want to use nargs instead of comma-separated values in string:
class StoreDictKeyPair(argparse.Action):
def __init__(self, option_strings, dest, nargs=None, **kwargs):
self._nargs = nargs
super(StoreDictKeyPair, self).__init__(option_strings, dest, nargs=nargs, **kwargs)
def __call__(self, parser, namespace, values, option_string=None):
my_dict = {}
print "values: {}".format(values)
for kv in values:
k,v = kv.split("=")
my_dict[k] = v
setattr(namespace, self.dest, my_dict)
parser.add_argument("--key_pairs", dest="my_dict", action=StoreDictKeyPair, nargs="+", metavar="KEY=VAL")
args = parser.parse_args(sys.argv[1:])
print args
Running
python arg_test4.py --key_pairs 1=2 a=bbb c=4 test=7 foo=bar
Outputs:
values: ['1=2', 'a=bbb', 'c=4', 'test=7', 'foo=bar']
Namespace(my_dict={'1': '2', 'a': 'bbb', 'c': '4', 'test': '7', 'foo': 'bar'})
Update argparse namespace with other namespace/dictionary
In the subparser
Action class, argparse.py
uses:
subnamespace, arg_strings = parser.parse_known_args(arg_strings, None)
for key, value in vars(subnamespace).items():
setattr(namespace, key, value)
to copy update namespace
with values from subnamespace
. argparse
uses the generic setattr
to set values, minimizing assumptions about valid names.
You might also be able to use
namespace.__dict__.update(subnamespace.__dict__)
but I haven't tested it.
Unpacking arguments from argparse
https://docs.python.org/3/library/argparse.html#the-namespace-object
This class is deliberately simple, just an object subclass with a readable string representation. If you prefer to have dict-like view of the attributes, you can use the standard Python idiom, vars():
>>>
>>> parser = argparse.ArgumentParser()
>>> parser.add_argument('--foo')
>>> args = parser.parse_args(['--foo', 'BAR'])
>>> vars(args)
{'foo': 'BAR'}
Note that one of the big advances, or changes at least, from optparse
to argparse
is that positional arguments, such as yours, are treated the same as optionals. They both appear in the args
Namespace
object. In optparse
, positionals are just the left overs from parsing defined options. You could get the same effect in argparse
by omiting your arguments and using parse_known_args
:
parser = argparse.ArgumentParser()
args, extras = parser.parse_known_args()
args
is now a Namespace, and extras
a list. You could then call your function as:
myfoo(*extras, **vars(args))
For example:
In [994]: import argparse
In [995]: def foo(*args, **kwargs):
.....: print(args)
.....: print(kwargs)
.....:
In [996]: parser=argparse.ArgumentParser()
In [997]: parser.add_argument('-f','--foo')
Out[997]: _StoreAction(option_strings=['-f', '--foo'], dest='foo', nargs=None, const=None, default=None, type=None, choices=None, help=None, metavar=None)
In [998]: args,extras = parser.parse_known_args(['-f','foobar','arg1','arg2'])
In [999]: args
Out[999]: Namespace(foo='foobar')
In [1000]: extras
Out[1000]: ['arg1', 'arg2']
In [1001]: foo(*extras, **vars(args))
('arg1', 'arg2')
{'foo': 'foobar'}
That same argparse
paragraph shows that you can define your own Namespace
class. It wouldn't be hard to define one that behaves like a dictionary (for use as **args
) and as namespace. All argparse
requires is that it works with getattr
and setattr
.
In [1002]: getattr(args,'foo')
Out[1002]: 'foobar'
In [1004]: setattr(args,'bar','ugg')
In [1005]: args
Out[1005]: Namespace(bar='ugg', foo='foobar')
another standard Python feature lets me pass vars(args)
as a tuple:
In [1013]: foo(*vars(args).items())
(('foo', 'foobar'), ('bar', 'ugg'))
{}
For a similar answer from last January: https://stackoverflow.com/a/34932478/901925
Neatly pass positional arguments as args and optional arguments as kwargs from argpase to a function
There I give ideas on how to separate out 'positionals' from 'optionals' after parsing.
Here's a custom namespace class that includes, in its API, a means of returning itself as a dictionary:
In [1014]: class MyNameSpace(argparse.Namespace):
......: def asdict(self):
......: return vars(self)
......:
In [1015]: args = parser.parse_args(['-f','foobar'], namespace=MyNameSpace())
In [1016]: args
Out[1016]: MyNameSpace(foo='foobar')
In [1017]: foo(**args.asdict())
()
{'foo': 'foobar'}
Another idea - use one of the multiple nargs
(2,'*','+') for the positional argument. Then you have only one name to type when passing it to your function.
parser.add_argument('pos',nargs='+')
args = ...
args.pos # a list, possibly empty
foo(*args.pos, **vars(args))
How to store an 'args.foo' value to a 'bar' variable?
As others have said, removing the line referencing args.learning_rate
will lead to others finding your code cryptic or confusing.
But something like this could be used in code golfing, so I will offer a 'cryptic' way of doing this under the assumption that you have several arguments that you do not want to have to reassign line-by-line.
You could acquire the dictionary of args
using the vars()
built-in function or __dict__
attribute.
Please reference What is the right way to treat Python argparse.Namespace() as a dictionary.
>>> import argparse
>>> args = argparse.Namespace()
>>> args.foo = 1
>>> args.bar = [1,2,3]
>>> d = vars(args)
>>> d
{'foo': 1, 'bar': [1, 2, 3]}
Afterwards you could convert these keys to variables and assign the values to the variable like so:
for k, v in d.items():
exec(f'{k} = {v}')
print(foo) # 1
print(bar) # [1, 2, 3]
Please see Using a string variable as a variable name for additional insight to why exec()
may be bad practice and setattr
may be more appropriate if you resort to this method.
Python Command Args
I'm not entirely sure what your goal is. But if that's literally all you have to do, you don't have to get very complicated:
import sys
print int(sys.argv[1]) + 2
Here is the same but with some nicer error checking:
import sys
if len(sys.argv) < 2:
print "Usage: %s <integer>" % sys.argv[0]
sys.exit(1)
try:
x = int(sys.argv[1])
except ValueError:
print "Usage: %s <integer>" % sys.argv[0]
sys.exit(1)
print x + 2
Sample usage:
C:\Users\user>python blah.py
Usage: blah.py <integer>
C:\Users\user>python blah.py ffx
Usage: blah.py <integer>
C:\Users\user>python blah.py 17
19
Python: load variables in a dict into namespace
Consider the Bunch
alternative:
class Bunch(object):
def __init__(self, adict):
self.__dict__.update(adict)
so if you have a dictionary d
and want to access (read) its values with the syntax x.foo
instead of the clumsier d['foo']
, just do
x = Bunch(d)
this works both inside and outside functions -- and it's enormously cleaner and safer than injecting d
into globals()
! Remember the last line from the Zen of Python...:
>>> import this
The Zen of Python, by Tim Peters
...
Namespaces are one honking great idea -- let's do more of those!
Use the current namespace with pars_args() in the argparse package in Python3
You may be confusing 2 uses of 'namespace'.
One namespace
is the dictionary that holds the variables of this module or function.
parser.parse_args()
creates an argparse.Namespace
object, and puts its values in it, using setattr
. This class definition is pretty simple.
parser.parse_args(namespace=myNamespace)
should work with any object that accepts the setattr
, getattr
and hasattr
methods. A dictionary does not work.
If given a dictionary the first error I get is in
setattr(namespace, action.dest, default)
AttributeError: 'dict' object has no attribute 'checked'
Are you asking this because you want to put the argparse
attributes directly in the local namespace dictionary?
You can convert a Namespace to a dictionary with vars(args)
. And you can add those items to another dictionary with update
(e.g. locals().update(vars(args))
).
Or if you have a function that takes **kwargs
, you could use: foo(**vars(args))
to put those arguments into the function's namespace. This does a better job of localizing the change. It also lets you define the variables with the normal keyword syntax.
Related Topics
"Ssl: Certificate_Verify_Failed" Error When Scraping Https://Www.Thenewboston.Com/
When Installing Pyaudio, Pip Cannot Find Portaudio.H in /Usr/Local/Include
Weird Behavior: Lambda Inside List Comprehension
How to Make a Python Script Executable
Printing Without Newline (Print 'A',) Prints a Space, How to Remove
Region: Ioerror: [Errno 22] Invalid Mode ('W') or Filename
Query Mongodb on Month, Day, Year... of a Datetime
How to Get All Combinations of Length N in Python
Repeat Rows in Data Frame N Times
Check for Identical Rows in Different Numpy Arrays
How to Open Multiple Webpages in Separate Tabs Within a Browser Using Selenium-Webdriver and Python
How to Implement Band-Pass Butterworth Filter with Scipy.Signal.Butter
Detect Text Region in Image Using Opencv
How to Wrap Every Method of a Class
Remove Duplicate Rows from Pandas Dataframe Where Only Some Columns Have the Same Value