This may be a simple question, but I’m having trouble making a unique search for it.
I have a class that defines a static dictionary, then attempts to define a subset of that dictionary, also statically.
So, as a toy example:
class example(object):
first_d = {1:1,2:2,3:3,4:4}
second_d = dict((k,first_d[k]) for k in (2,3))
This produces NameError: global name 'first_d' is not defined
How should I be making this reference? It seems this pattern works in other cases, eg:
class example2(object):
first = 1
second = first + 1
A basic list comprehension has the following syntax
When a list comprehension occurs inside a class, the attributes of the class
can be used in
iterable. This is true in Python2 and Python3.However, the attributes of the class can be used (i.e. accessed) in
expressionin Python2 but not in Python3.The story is a bit different for generator expressions:
While the class attributes can still be accessed from
iterable, the class attributes are not accessible fromexpression. (This is true for Python2 and Python3).This can all be summarized as follows:
(Dict comprehensions behave the same as generator expressions in this respect.)
Now how does this relate to your question:
In your example,
a
NameErroroccurs becausefirst_dis not accessible from theexpressionpart of a generator expression.A workaround for Python2 would be to change the generator expression to a list comprehension:
However, I don’t find this a very comfortable solution since this code will fail in Python3.
You could do as Joel Cornett suggests:
since this uses
first_din theiterablerather than theexpressionpart of the dict comprehension. But this may loop through many more items than necessary iffirst_dcontains many items. Neverthess, this solution might be just fine iffirst_dis small.In general, you can avoid this problem by defining a helper function which can be defined inside or outside the class:
Functions work because they define a local scope and
variables in this local scope can be accessed from within the dict comprehension.
This was explained here, but I am not entirely comfortable with this since it does not explain why the
expressionpart behaves differently than theiterablepart of a list comprehension, generator expression or dict comprehension.Thus I can not explain (completely) why Python behaves this way, only that this is the way it appears to behave.