scope of generators, class variables, resulting in global na

Jon Clements joncle at googlemail.com
Wed Feb 24 10:45:05 EST 2010


On Feb 24, 12:21 pm, "Alf P. Steinbach" <al... at start.no> wrote:
> * Nomen Nescio:
>
> > Hello,
>
> > Can someone help me understand what is wrong with this example?
>
> > class T:
> >   A = range(2)
> >   B = range(4)
> >   s = sum(i*j for i in A for j in B)
>
> > It produces the exception:
>
> > <type 'exceptions.NameError'>: global name 'j' is not defined
>
> Which Python implementation are you using?
>
> I can't reproduce the error message that you cite.
>
> <example>
> C:\test> py2
> Python 2.6.4 (r264:75708, Oct 26 2009, 08:23:19) [MSC v.1500 32 bit (Intel)] on
> win32
> Type "help", "copyright", "credits" or "license" for more information.
>  >>> class T:
> ...   A = range(2)
> ...   B = range(4)
> ...   s = sum(i*j for i in A for j in B)
> ...
> Traceback (most recent call last):
>    File "<stdin>", line 1, in <module>
>    File "<stdin>", line 4, in T
>    File "<stdin>", line 4, in <genexpr>
> NameError: global name 'B' is not defined
>  >>> exit()
>
> C:\test> py3
> Python 3.1.1 (r311:74483, Aug 17 2009, 17:02:12) [MSC v.1500 32 bit (Intel)] on
> win32
> Type "help", "copyright", "credits" or "license" for more information.
>  >>> class T:
> ...   A = range(2)
> ...   B = range(4)
> ...   s = sum(i*j for i in A for j in B)
> ...
> Traceback (most recent call last):
>    File "<stdin>", line 1, in <module>
>    File "<stdin>", line 4, in T
>    File "<stdin>", line 4, in <genexpr>
> NameError: global name 'B' is not defined
>  >>> exit()
>
> C:\test> _
> </example>
>
> Reason for the NameError:
>
> The above is a /generator expression/, evaluated in a class definition.
>
> The docs have a similar example but I'm sorry, I'm unable to find it! Anyway the
> generator expression is evaluated as if its code was put in function. And from
> within the scope of that function you can't access the class scope implicitly,
> hence, no access to 'B'.
>
> > The exception above is especially confusing since the following similar example
> > (I just replaced the generator by an explicit array) works:
>
> > class T:
> >   A = range(2)
> >   B = range(4)
> >   s = sum([(i*j) for i in A for j in B])
>
> > (BTW, the class scope declarations are intentional).
>
> > Thanks, Leo.
>
> This is a /list comprehension/, not a generator expression (although
> syntactically it's almost the same).
>
> It obeys different rules.
>
> Essentially the generator expression produces a generator object that you may
> name or pass around as you wish, while the comprehension is just a syntactical
> device for writing more concisely some equivalent code that's generated inline.
>
> However, apparently the rules changed between Python 2.x and Python 3.x.
>
> In Python 3.x also the list comprehension fails in a class definition:
>
> <example>
> C:\test> py2
> Python 2.6.4 (r264:75708, Oct 26 2009, 08:23:19) [MSC v.1500 32 bit (Intel)] on
> win32
> Type "help", "copyright", "credits" or "license" for more information.
>  >>> class T:
> ...   A = range(2)
> ...   B = range(4)
> ...   s = sum([(i*j) for i in A for j in B])
> ...
>  >>> exit()
>
> C:\test> py3
> Python 3.1.1 (r311:74483, Aug 17 2009, 17:02:12) [MSC v.1500 32 bit (Intel)] on
> win32
> Type "help", "copyright", "credits" or "license" for more information.
>  >>> class T:
> ...   A = range(2)
> ...   B = range(4)
> ...   s = sum([(i*j) for i in A for j in B])
> ...
> Traceback (most recent call last):
>    File "<stdin>", line 1, in <module>
>    File "<stdin>", line 4, in T
>    File "<stdin>", line 4, in <listcomp>
> NameError: global name 'B' is not defined
>  >>> exit()
>
> C:\test> _
> </example>
>
>  From one point of view it's good that Py3 provides about the same behavior for
> generator expressions and list comprehensions.
>
> But I'd really like the above examples to Just Work. :-)
>
> Cheers & hth.,
>
> - Alf


s = sum( i*j for i,j in iterools.product(A, B) ) is a possible work
around.

Which could generalise to (something like):

s = sum( reduce(op.mul, seq) for seq in product(A, B, B, A) )

Cheers,

Jon.



More information about the Python-list mailing list