On Fri, Dec 28, 2018 at 3:31 AM Ian Kelly <ian.g.ke...@gmail.com> wrote: > > On Wed, Dec 26, 2018 at 11:21 PM Chris Angelico <ros...@gmail.com> wrote: > > > > On Thu, Dec 27, 2018 at 1:56 PM <jf...@ms4.hinet.net> wrote: > > > > > > I saw the code below at stackoverflow. I have a little idea about the > > > scope of a class, and list comprehension and generator expressions, but > > > still can't figure out why Z4 works and Z5 not. Can someone explain it? > > > (in a not-too-complicated way:-) > > > > > > class Foo(): > > > XS = [15, 15, 15, 15] > > > Z4 = sum(val for val in XS) > > > try: > > > Z5 = sum(XS[i] for i in range(len(XS))) > > > except NameError: > > > Z5 = None > > > > > > print(Foo.Z4, Foo.Z5) > > > >>> 60 None > > > > > > > Class scope is special, and a generator expression within that class > > scope is special too. There have been proposals to make these kinds of > > things less special, but the most important thing to remember is that > > when you create a generator expression, it is actually a function. > > Remember that a function inside a class statement becomes a method, > > and that inside the method, you have to use "self.X" rather than just > > "X" to reference class attributes. That's what's happening here. > > Except you can't use "self" either because the class doesn't exist yet > at the time the generator expression is being evaluated.
Well, yes. But that's the easiest way to highlight the difference of scope. > Nor can you > use "self" generally even if you wait until the class does exist > before you iterate over the generator, because while a generator > expression may scope like a function, and may under the hood be > implemented as a function, a generator object is not a function object > and will not create a method. Hmm. It creates a function which is called at class scope. Based on disassembly, I can't see a difference between the function created for a genexp and the one created for a method. What IS true, though, is that there's no way to pass arguments to the genexp, which means that it won't be passed a 'self'. So if you wait till the class exists before iterating over the generator, you can name the class, but you can't use self: >>> class Foo: ... word = "spam" ... genexp = (l.upper() for shim in [...] for l in Foo.word) ... >>> list(Foo.genexp) ['S', 'P', 'A', 'M'] I would personally have preferred for the official Python language definition to have described comprehensions and genexps as creating a scope boundary, without baking into the language "they're hidden, implicit functions". But that ship has sailed, and when I debated the point, all Pandora's box got opened. ChrisA -- https://mail.python.org/mailman/listinfo/python-list