This question already has an answer here:
-
Accessing class variables from a list comprehension in the class definition
4 answers
I have this code in a file
class Sudoku(dict):
COLUMNS = [
{(x, y) for y in xrange(9)} for x in xrange(9)
]
When I run python broken.py
, I get the traceback:
Traceback (most recent call last):
File "U:\broken.py", line 1, in <module>
class Sudoku(dict):
File "U:\broken.py", line 3, in Sudoku
{(x, y) for y in xrange(9)} for x in xrange(9)
File "U:\broken.py", line 3, in <setcomp>
{(x, y) for y in xrange(9)} for x in xrange(9)
NameError: global name 'x' is not defined
[Finished in 0.1s with exit code 1]
I don't really see the problem here. Isn't x
defined in the comprehension?
What's stranger is how this seems to execute without an error when pasted directly into the python interpreter...
EDIT: This works if I use a list comprehension rather than a set comprehension
I've filed a bug here. This is still broken by design in python 2.7.5.
From the bug report:
In Python 2, list comprehensions don't have their own scope, so the x
in your initial example lives at class scope. However, the set comprehension does have its own scope. By design, a variable defined at class scope is not visible to inner scopes inside that class.
In Python 3, this works because the list comprehension has its own scope.
Wild guess, but Python set comprehensions were introduced with Python 2.7 and 3.0: would you happen to use an older version to execute your script, and a recent one as your interpreter ?
After looking at this section of the Python documentation, I see no explanation for this behavior. Furthermore, the fact that it works with list comprehension clearly show that it is not a scope issue.
I see only two possible reasons:
- A bug in the set comprehensions implementation
- The use of an anterior Python version which does not support set comprehensions.
I'm afraid I have no idea why your code is not working, however, the following works and gives you what you want:
class Sudoku(dict):
COLUMNS = [
set([(x, y) for y in xrange(9)]) for x in xrange(9)
]
Maybe some of the python gurus on this site can enlighten us as to why your code snippet fails.
I wish I could give a theoretical explanation, but this works:
class Sudoku(dict):
def __init__(self):
self.COLUMNS = [
{(x, y) for y in xrange(9)} for x in xrange(9)
]
if __name__ == "__main__":
s = Sudoku()
print s.COLUMNS
Maybe this it what you really want:
[[{x:y} for x in xrange(9)] for y in xrange(9)]