class Some(object):
tokens = [ ... list of strings ... ]
untokenized = [tokens.index(a) for a in [... some other l
As Wooble says, the issue is that classes don't have a lexical scope (actually, in either Python 2 or Python 3). Instead, they have a local namespace that does not constitute a scope. This means that expressions within the class definition have access to the content of the namespace:
class C:
a = 2
b = a + 2 # b = 4
but scopes introduced within the body of the class do not have access to its namespace:
class C:
a = 2
def foo(self):
return a # NameError: name 'a' is not defined, use return self.__class__.a
The difference between Python 2 and Python 3 is that in Python 2 list comprehensions do not introduce a new scope:
[a for a in range(3)]
print a # prints 2
whereas in Python 3 they do:
[a for a in range(3)]
print(a) # NameError: name 'a' is not defined
This was changed in Python 3 for a couple of reasons, including to make list comprehensions behave the same way as generator-expressions (genexps); (a for a in range(3))
has its own scope in both Python 2 and Python 3.
So, within the body of a class, a Python 2 genexp or a Python 3 listcomp or genexp introduces a new scope and therefore does not have access to the class-definition local namespace.
The way to give the genexp/listcomp access to names from the class-definition namespace is to introduce a new scope, using a function or a lambda:
class C:
a = 2
b = (lambda a=a: [a + i for i in range(3)])()
eval
issueThe issue with your eval
example is that eval
by default evaluates its argument in the local scope; because Python 2 list comprehensions have the above behaviour of sharing the enclosing scope the eval
can access the method scope, but a genexp or Python 3 listcomp local scope only has whatever the compiler can tell is required from the enclosing scope (since a genexp/listcomp scope is a closure):
def bar(x):
return list(eval('x') + x for i in range(3))
bar(5) # returns [10, 10, 10]
def baz(x):
return list(eval('x') for i in range(3))
baz(5) # NameError: name 'x' is not defined
As Martijn says, instead of eval
you should use getattr
.