2

Say I have a namespace args that I obtain from calling parser.parse_args(), which parses the command line arguments.

How can I import all variables from this namespace to my current namespace?

e.g.

parser.add_argument('-p', '--some_parameter', default=1)

args = parser.parse_args()

# ... code to load all variables defined in the namespace args ...

print some_parameter

I could certainly do:

some_parameter = args.some_parameter

but if I have a large number of parameters I would need one such line for each parameter.

Is there another way of importing variables from a namespace without having to go through them one by one?

PS: from args import * does not work.

PS2: I am aware that this is a bad practice, but this can help in some corner cases, such us when prototyping code and tests very quickly.

Amelio Vazquez-Reina
  • 91,494
  • 132
  • 359
  • 564
  • You could loop over `__dict__` or use `inspect`... – Silas Ray Feb 04 '13 at 22:47
  • 1
    Or just `locals().update(namespace._get_kwargs())`. – abarnert Feb 04 '13 at 22:51
  • 2
    Why do you _want_ to do this? Why not just access `args.some_parameter`? (Especially since, in a non-trivial program, you're probably going to want to pass the options to other functions, which means if you've got lots of options you're probably going to end up building a `dict` or other object equivalent to the namespace you pulled apart…) – abarnert Feb 04 '13 at 22:52
  • 1
    you can also use `vars(args)` to get a `dict` – Francesco Montesano Feb 04 '13 at 22:54

2 Answers2

5

Update your local namespace with the result of the vars() function:

globals().update(vars(args))

This is generally not that great an idea; leave those attributes in the namespace instead.

You could create more problems than you solved with this approach, especially if you accidentally configure arguments with a dest name that shadows a built-in or local you care about, such as list or print or something. Have fun hunting down that bug!

Tim Peters already stated this in his Zen of Python:

Namespaces are one honking great idea -- let's do more of those!

Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
  • +1. I forgot that `vars(namespace)` and `namespace._get_kwargs()` will return the same thing. – abarnert Feb 04 '13 at 22:53
  • 1
    It's not merely a bad idea that makes for hard-to-read code--it's also a rich source of unintended bugs and security holes. You could easily overwrite globals and builtins--e.g. suppose you have a parameter named `list`? Or a parameter which can't be an identifier, like `2my-param`? – Francis Avila Feb 04 '13 at 22:59
  • 2
    @FrancisAvila: It's not necessarily a security hole, provided the parser has been set up with sane argument names. You cannot inject *arbitrary* argument destinations in any case. Besides, the user of this program already has local-user access to be able to run it.. – Martijn Pieters Feb 04 '13 at 23:00
  • tsk,tsk. You shouldn't modify `locals`. quoting from the [documentation](http://docs.python.org/2/library/functions.html#locals) "The contents of this dictionary should not be modified; changes may not affect the values of local and free variables used by the interpreter." – mgilson Feb 05 '13 at 21:06
  • @mgilson: That mostly applies to functions; grab a parent function in the current call stack and try to update it's `f_locals` structure with new values for example and it'll fail.. But for modules (where `locals()` == `globals()` anyway, it'll work just fine. :-) – Martijn Pieters Feb 05 '13 at 22:00
  • @MartijnPieters -- my understanding is that anywhere where `locals != globals`, it will fail -- in which case, you might as well change your answer to be `globals` instead of `locals` and not pretend like `locals` that works for this -- But that's just my opinion ... (the rest of the answer is good) – mgilson Feb 05 '13 at 22:02
  • @mgilson: No, in many/most places `locals()` is actually writable (including adding *new* keys), but I'll update it to use `globals()` instead. – Martijn Pieters Feb 05 '13 at 22:04
  • FYI -- I came across this in another question which referenced it (http://stackoverflow.com/questions/14716727/picklable-data-containers-that-are-dumpable-in-the-current-namespace/14716991#14716991). I solved the "general" problem using an `exec` hack with a broad disclaimer that it isn't what OP actually wants to do. – mgilson Feb 05 '13 at 22:06
  • @mgilson: but, but, `exec` updates `locals()` just as much.. When you omit both globals and locals from the statement, the C code just runs `PyEval_GetLocals`, *exactly* what `locals()` does. – Martijn Pieters Feb 05 '13 at 22:14
0

Probably the worst idea ever: since you can pass an arbitrary object to parse_args(), pass the __builtins__ module, so that all attributes can be looked up as local variables.

p = argparse.ArgumentParser()
p.add_argument("--foo")
p.parse_args( "--foo bar".split(), __builtins__)
print foo

This will even "work" for parameters whose destinations aren't valid Python identifiers:

# To use the example given by Francis Avila in his comment on Martijn Pieters' answer
getattr(__builtins__, '2my-param')
chepner
  • 497,756
  • 71
  • 530
  • 681