How to Convert dictionary into local variables inside the function?

I have the dictionary which passing through function which has to convert into local variables where i can use those variables for further operations. That dictionary will be dynamic…

def dictlocalconverter(hash):
       for k, v in hash.items():
            locals()[k] = v
       return d

dictn = {"a":10,"b":11,"d":"25"}
dictlocalconverter(dictn)

hash() Returns the hash value of the object (if it has one). Is that what you want?

Or is this what you intended?

def dictlocalconverter(dictn):
    for k, v in dictn.items():
        locals()[k] = v
    return dictn.get('d')

dictn = {"a":10,"b":11,"d":"25"}
dictlocalconverter(dictn)

Function scopes use fast local variables, which in CPython are implemented using an array of object references that’s allocated on the stack of a call frame. Each local variable and each free variable (excluding the global and builtins scopes) is mapped to an index of the fast locals array.

In this case, the mapping that’s returned by the builtin locals() function is just a snapshot of the current values of local variables and free variables. This mapping gets updated each time that locals() is called. There is no support to dynamically create a new fast local variable and no supported way in pure Python (i.e. excluding the C API) to dynamically update the value of a fast local variable. This is in sharp contrast to support for dynamic local variables at the module level or in a class body, both of which directly use the mapping that’s returned by locals() for their local variables.

If it’s just a matter of more convenient access to known keys in a dict, you could use types.SimpleNamespace(). For example:

>>> dictn = {"a":10,"b":11,"d":"25"}
>>> ns = types.SimpleNamespace(**dictn)
>>> ns.d
'25'
1 Like

If I understand it correctly you want to access dict values not through the [] operator and key names but using the keys directly as identifiers.

You suggest that you want to inject the dictionary keys as local variables. This is certainly a bad and practically impossible practice (as Eryk explains).

An alternative with almost the same functionality but with almost no of the bad consequences is to alter the dict class so that you can use the dictionary keys as object attributes. Of course this way you can access only keys which are named as valid Python identifiers:

class AttrDict(dict):
    """Provide dictionary with items accessible as object attributes."""
    def __getattr__(self, attr: str) -> Any:
        try:
            return self[attr]
        except KeyError as exception:
            raise AttributeError(f'AttrDict has no key {attr!r}') from exception

    def __setattr__(self, attr: str, value: Any) -> None:
        self[attr] = value

    def __delattr__(self, attr: str) -> Any:
        try:
            del self[attr]
        except KeyError as exception:
            raise AttributeError(f'AttrDict has no key {attr!r}') from exception

Then you can do this:

dictn = AttrDict({"a":10,"b":11,"d":"25"})
print(f"{dictn.a = }, {dictn.b = }, {dictn.d = }")
dictn.a = 42
dictn.c = 'hello'
print(f"{dictn.a = }, {dictn.b = }, {dictn.c = }, {dictn.d = }")

output:

dictn.a = 10, dictn.b = 11, dictn.d = '25'
dictn.a = 42, dictn.b = 11, dictn.c = 'hello', dictn.d = '25'

Comparison to Eryk’s solution (types.SimpleNamespace):

  • You define a new class.
  • The class is a sub-type of dict and still behaves like a dict.
  • You do not need to convert between dict and SimpleNamespace by creating a new objects.

Whether this is a good idea or a bad idea, it is no longer possible in Python 3. locals() returns a snapshot of the local variables, not a reference to the actual namespace used for storage, and so any modifications to the snapshot are not reflected back to the variables.

I recommend you re-consider your strategy and find another way to write this program.

Alternatively, you could downgrade to Python 2, which is unsupported, and try it there. My memory is that it works as you want in Jython and IronPython, and sometimes works in CPython, according to arcane and undocumented implementation details.

Fundamentaly, the Python language does not guarantee that you can modify local variables by writing to locals(). Even if you find a version of Python where it works, it will not be portable code, and will probably change in the future.

Its orthogonal to @sai_ram_basa 's main issue, but just to be clear, hash is a builtin function, not a keyword or singleton constant (as are True, False and None), so in Python it can be shadowed and redefined like any other name.

In that sense, your code sample is not really any clearer than the original, and arguably less so, as it shadows a name from the global scope at the function local scope, which has a high potential to cause confusion (particularly considering it seems to have confused you yourself), since these are two different names that may or may not refer to the same underlying object at any given point.

The original is not ideal either, of course, since readers (like yourself) could easily be confused and assume that it refers to the builtin function rather than a local variable, it makes the builtin non-trivial to access should it be needed (one would have to do import builtins; builtins.hash) and it causes editors and IDEs to highlight it incorrectly (though that also makes it easy to spot variable names that should be avoided).

Therefore, the solution is to rename the variable to something else appropriate, such a a_dict, locals_dict, etc., or better yet, have the appropriate function (the constructor of the namespace, custom dict, etc) take **kwargs instead (which would automatically ensure the keys are valid Python names), aside from the other changes.

Thank you.

The point behind my post was more about the modified return which does (so far as I can tell) what the OP was looking for, but as the OP seems to have gone AWAL, I can only guess at this point.

Yes, I am confused by his use (or rather his misuse) of hash and again can only guess as to his intentions.

Clearly I need to stop with my guessing here and let other, more experienced coders answer these types of questions.

“hash” is short for “hash table”, which is a data structure.

Dicts are a kind of hash table.

Python uses dicts as “namespaces”, a table of variable names and values. (That is, in modules and classes, but not for function local variables, which use a more optimised table.)

So the Original Poster used “hash” to mean “table of variable names and values”. That is all.

1 Like

If so, this wasn’t clear from your post, sorry, given it stated

The OP is simply using hash as the local name of a dictionary (often called a hash/hashmap/hash table in other contexts); neither their code nor description has any plausible connection with the relatively rarely used builtin function hash(). Given the evident potential (and indeed, realized) confusion, I wanted to clarify that point.

And in the part of your post where you discuss the modified return, it likewise appears to not really correspond to what the OP has stated in their post; in the original, the intention of the return was evidently to attempt to test whether after populating locals() with the contents of dictn, items in the dictionary (such as d) could be accessed directly as local variable names, which your proposed modification subverts.

I wouldn’t consider not responding for merely two days over a Friday and a Saturday to be “AWAL [sic]”, but to each their own.

As explained in my previous reply, hash is simply a local variable name for the passed dictionary, and everything in the OP’s usage is fully consistent with that; it is merely coincidental that it happens to shadow a relatively rarely used builtin. While potentially confusing to others, it is not a “misuse” of anything per-say, just one suboptimal naming choice (among several others), and is really a minor nit compared to the much more important issues with the code.

I interpreted the use of return d as just an example of using a dynamic local variable named d. In this case, the original poster would also expect to be able to use local variables named a and b. This is not supported in a function scope in Python 3.x. In 2.x it’s possible in a non-nested function if fast locals are disabled in the scope (e.g. by the use of a from * import ... statement). That said, using dynamic local variables (i.e. updating locals() with a mapping) should kept to a minimum even in contexts in which it’s technically supported. The source of the variable and its value isn’t clearly understood when reading the function definition. Maybe the variable isn’t actually local (i.e. an undeclared variable from an outer scope). If it is a dynamic local, there could be multiple updates of locals(), so from where does it originate? This is like using global variables… but on steroids.

2 Likes