How can I load all keys from dict as local variables, better aproach?

Providing this dictionary:

>>> options = {'DATABASES': {'default': {'ENGINE': 'django.db.backends.sqlite3'}}} 

What would be the best way to get this ?:

 >>> foo(options) >>> print DATABASES {'default': {'ENGINE': 'django.db.backends.sqlite3'}} 

I solve this as locals (). update (options), but I was thinking if there is a better solution.

+7
source share
4 answers
 import inspect allowed_vars = set(["min_", "max_", "path", ...]) def update_globals(dic): caller_frame = inspect.currentframe(1) globals = caller_frame.f_globals # here, you _could_ simply do globals.update(dic) # but it is evil for key, value in dic.items(): #here you should carefully verify each key, and value for not #not dangerous pairs, with stuff like: #if key not in allowed_vars: # sys.stderr.write("Warning: invalid variable in configuration update\n") # continue #if type(value) not in (string, int, float): # #(issue error) # continue globals[key] = value 

Example:

 >>> a Traceback (most recent call last): File "<stdin>", line 1, in <module> NameError: name 'a' is not defined >>> update_globals({"a": 5}) >>> a 5 

update 2016-06 A few weeks ago I put together an extradict Python package - it is available on pypi now . One of its functions is the MapGetter context MapGetter , which allows you to accurately query by doing something:

 from extradict import MapGetter def myfunc(): options = {'DATABASES': {'default': {'ENGINE': 'django.db.backends.sqlite3'}}} with MapGetter(options) as options: from options import DATABASES ... 

And other normal "from .... import ...." are used, but from a dictionary or mapping object (including the default dict).

+7
source

As goldmab noted, changing the locals () function inside the function will not work:

 SyntaxError: invalid syntax >>> def foo(): ... locals().update({'a': 1}) ... print a ... >>> foo() Traceback (most recent call last): File "<stdin>", line 1, in <module> File "<stdin>", line 3, in foo NameError: global name 'a' is not defined 

This is also not a very clean way, but it will accomplish this task:

 >>> def foo(): ... options = {'DATABASES': {'default': {'ENGINE': 'django.db.backends.sqlite3'}}} ... for k, v in options.items(): ... exec('%s = v' % k) ... print DATABASES ... >>> foo() {'default': {'ENGINE': 'django.db.backends.sqlite3'}} 

Note that each key in your dict should be in order as a variable. So, for example, if the dictionary contains "DATABASE-USERNAME" as the key, an attempt to assign a variable to it will throw an exception. In addition, it will make you vulnerable to code injection if you get a dictionary of options from an untrusted source. (The key might say something like: "import os; os.system ('sudo adduser scriptkiddie'); ..."

+3
source

I think you want just:

 globals().update(**options) 
+3
source

You cannot change function locators at runtime because the list of local variable names is a static part of the compiled function object.

 >>> def a(): b = 5 ... >>> a.func_code.co_varnames ('b',) 

This will work in the global scope only because locals() matches globals() there, and global variables are stored in a dictionary that is dynamic (unlike function locales).

 >>> locals() is globals() True 

It looks like you are updating the values ​​in the Django settings module from another source. I would not say that this is necessarily bad, but for clarity, use globals() instead of locals() .

0
source

All Articles