This issue tracker has been migrated to GitHub, and is currently read-only.
For more information, see the GitHub FAQs in the Python's Developer Guide.

classification
Title: Error referencing local variables in dict comprehensions inside class definitions
Type: behavior Stage: resolved
Components: Interpreter Core Versions: Python 3.6
process
Status: closed Resolution: duplicate
Dependencies: Superseder: improper scope in list comprehension, when used in class declaration
View: 3692
Assigned To: Nosy List: Alex Mashianov, mark.dickinson, serhiy.storchaka
Priority: normal Keywords:

Created on 2018-08-27 08:42 by Alex Mashianov, last changed 2022-04-11 14:59 by admin. This issue is now closed.

Messages (4)
msg324156 - (view) Author: Alex Mashianov (Alex Mashianov) Date: 2018-08-27 08:42
This code:
class A:
    a = 1
    b = {str(x): x for x in range(5) if x != a}

Produces following error:
Traceback (most recent call last):
  File "<input>", line 1, in <module>
  File "<input>", line 3, in A
  File "<input>", line 3, in <dictcomp>
NameError: name 'a' is not defined


Which i think it shouldn't produce. Issue occurs only in dict comprehensions inside class definitions referencing class attributes(which are in local scope during definition).
msg324158 - (view) Author: Alex Mashianov (Alex Mashianov) Date: 2018-08-27 08:45
Update: any class definition comprehension referencing local variables inside filtering block produces this error.
msg324159 - (view) Author: Serhiy Storchaka (serhiy.storchaka) * (Python committer) Date: 2018-08-27 09:30
This is a duplicate of issue3692.
msg324162 - (view) Author: Mark Dickinson (mark.dickinson) * (Python committer) Date: 2018-08-27 10:00
[I wrote this before Serhiy posted his reply; sending it anyway, in case the doc links are useful.]

This is documented, by-design behaviour. Essentially name resolution skips class scopes.

See https://docs.python.org/3/reference/executionmodel.html#resolution-of-names, and particularly the example at the end of that section, which is very similar to your example.

See also: https://docs.python.org/3/reference/expressions.html#displays-for-lists-sets-and-dictionaries, and in particular this part:

> However, aside from the iterable expression in the leftmost for clause,
> the comprehension is executed in a separate implicitly nested scope.
> This ensures that names assigned to in the target list don’t “leak” into
> the enclosing scope.

That "leftmost for clause" bit explains why, in the following example, the first comprehension is evaluated successfully, but the second raises a `NameError`.

>>> class A:
...     a = 3
...     b = [x+y for x in range(a) for y in range(3)]  # okay
...     c = [x+y for x in range(3) for y in range(a)]  # raises
History
Date User Action Args
2022-04-11 14:59:05adminsetgithub: 78698
2018-08-27 10:01:47mark.dickinsonsetnosy: + serhiy.storchaka
2018-08-27 10:01:25mark.dickinsonsetsuperseder: improper scope in list comprehension, when used in class declaration
2018-08-27 10:00:55mark.dickinsonsetresolution: not a bug -> duplicate
stage: resolved
2018-08-27 10:00:14mark.dickinsonsetnosy: + mark.dickinson, - serhiy.storchaka
messages: + msg324162
resolution: duplicate -> not a bug

superseder: improper scope in list comprehension, when used in class declaration -> (no value)
stage: resolved -> (no value)
2018-08-27 09:30:55serhiy.storchakasetstatus: open -> closed

superseder: improper scope in list comprehension, when used in class declaration

nosy: + serhiy.storchaka
messages: + msg324159
resolution: duplicate
stage: resolved
2018-08-27 08:46:06Alex Mashianovsetversions: + Python 3.6, - Python 3.7
2018-08-27 08:45:44Alex Mashianovsetmessages: + msg324158
2018-08-27 08:42:26Alex Mashianovcreate