The difference is because in Python3, list-comprehensions use a separate variable scope than the surrounding code, while in Python 2, they share the same variables.
Add to that the peculiar thing of variables in class body, in which inner scopes, no matter if they are functions or generator expressions can't "see" nonlocal variables, and you get your error.
I think the easiest work around will be to run your generator inside a one-time lambda function, and pass the needed variables as parameters to it. Inside the lambda function, the usual scope-nesting rules in which inner scopes can see outer variables apply:
class Test(object):
base = 1000
a,b,c,d = (lambda base: [base+y for y in range(4)])(base)
Since Python 3 allows one to use a custom object as the namespace for the class body, it is also possible to create a namespace that is visible on the global scope. In that way, code in inner scopes in the class body can use the variables there.
This short metaclass and helper mapping can do it - and an easy way to avoid name clashing in the global scope is just to use the class name itself. This way, one also gains in readability:
class AttrDict(dict):
def __getattr__(self, attr):
return self.__getitem__(attr)
def __setattr__(self, attr, value):
self.__setitem__(attr, value)
class Namespace(type):
@classmethod
def __prepare__(metacls, name, bases, **kwargs):
import sys
module_globals = sys._getframe(1).f_globals
namespace = AttrDict()
module_globals[name] = namespace
return namespace
And now, you can write your code like this:
class Base(metaclass=Namespace):
x = 10
a, b, c, d = (i + Base.x for i in range(4))
del x