using locals() inside dictionary comprehension
Asked Answered
L

2

10

The following code doesn't work, I assume because the locals() variable inside the comprehension will refer to the nested block where comprehension is evaluated:

def f():
    a = 1
    b = 2
    list_ = ['a', 'b']
    dict_ = {x: locals()[x] for x in list_}
KeyError: 'a'

I could use globals() instead, and it seems to work, but that may come with some additional problems (e.g., if there was a variable from a surrounding scope that happens to have the same name).

Is there anything that would make the dictionary using the variables precisely in the scope of function f?

Note: I am doing this because I have many variables that I'd like to put in a dictionary later, but don't want to complicate the code by writing dict_['a'] instead of a in the meantime.

Limelight answered 1/11, 2010 at 0:46 Comment(2)
It works now, as of Python 3.12.Displeasure
Related: Can't use locals() in list comprehension in Python 3? (List comp behaviour changed between Python 2 and 3, but dict comp already had this behaviour.)Displeasure
C
9

You could perhaps do this:

def f(): 
    a = 1 
    b = 2 
    list_ = ['a', 'b'] 
    locals_ = locals()
    dict_ = dict((x, locals_[x]) for x in list_)

However, I would strongly discourage the use of locals() for this purpose.

Caricature answered 1/11, 2010 at 0:53 Comment(5)
I didn't think of this! And why is it bad to use locals() like this? I'm not using anything undocumented, am I?Limelight
It's not undocumented, but the use of locals() may trigger the compiler to generate less-than-optimal code for the function where it is referenced. For example, if the compiler determines that it can optimise out the use of some temporary variable (perhaps some other variable in the function unrelated to your dictionary), it might not be able to do that if locals() is used within the function. Also, by avoiding creating a dictionary first you're repeating yourself with (1) the assignment of each variable, and (2) the names in the list.Caricature
Then I am stuck: #4067963Limelight
Why use a generator expression instead of a dict comp? The dict comp is shorter, easier to read, and behaves the same way, no?Displeasure
@wjandrea: The answer is very simple - at the time this answer was written (2010), the dictionary comprehension syntax had just been introduced in the newest version of Python (2.7). Most people were not using the latest version.Caricature
S
6

You're right: the locals() inside the dict comprehension will refer to the comprehension's namespace.

One possible solution (if it hasn't already occurred to you):

f_locals = locals()
dict_ = {x : f_locals[x] for x in list_}
Syriac answered 1/11, 2010 at 0:54 Comment(1)
It works now, as of Python 3.12. You could add an update :)Displeasure

© 2022 - 2024 — McMap. All rights reserved.