Re: Ask for help about class variable scope (Re: Why doesn't a dictionary work in classes?)
jf...@ms4.hinet.net於 2018年12月28日星期五 UTC+8下午4時04分07秒寫道: > eryk sun at 2018/12/27 UTC+8 PM 6:58:33 wrote: > > On 12/27/18, jf...@ms4.hinet.net wrote: > > > > > > I still don't get it. When I change it to using list comprehension, the > > > problem is still there. (it now has no late-binding variable, right? :-) > > > > > class Too: > > > ... XS = [15, 15, 15, 15] > > > ... Z4 = [val for val in XS] > > > ... Z5 = [XS[0] for val in XS] > > > ... > > > Traceback (most recent call last): > > > File "", line 1, in > > > File "", line 4, in Too > > > File "", line 4, in > > > NameError: name 'XS' is not defined > > > > > > The problem confuse me is that is XS a local variable of the list > > > comprehension? > > > > XS is not a local variable in the scope of either comprehension. XS is > > local to the class statement's scope. For each comprehension, an > > iterator for the current object referenced by XS gets instantiated > > (early binding) and passed as an argument to the comprehension scope. > > If we disassemble the comprehension code, we find that this iterator > > argument has the creatively illegal name ".0". (The bytecode > > references it by its fast-locals-array index, not its weird name.) > > > > In the Z5 case, XS is a non-local variable (late binding) in the > > loop-body expression (left-hand side) of the comprehension. That's > > common for Python code. In every iteration of the loop, the > > interpreter looks up the object referenced by the name "XS", which can > > change at any time (e.g. by another thread). > > In Python document 4.2.2. Resolution of names, the last paragraph: > > "...A class definition is an executable statement that may use and define > names. These references follow the normal rules for name resolution with an > exception that unbound local variables are looked up in the global namespace. > ...The scope of names defined in a class block is limited to the class block; > it does not extend to the code blocks of methods – this includes > comprehensions and generator expressions since they are implemented using a > function scope". > > These statements reflect the following difference: > > >>> xy = [1,2] > >>> [dir() for i in xy] > [['.0', 'i'], ['.0', 'i']] > >>> [xy[0] for i in xy] > [1, 1] > > >>> class foo(): > ... xs = [1,2] > ... z4 = [dir() for i in xs] > ... > >>> foo().z4 > [['.0', 'i'], ['.0', 'i']] > >>> class foo(): > ... xs = [1,2] > ... z4 = [xs[0] for i in xs] > ... > Traceback (most recent call last): > File "", line 1, in > File "", line 3, in foo > File "", line 3, in > NameError: name 'xs' is not defined > >>> > > and it goes further: > > >>> [dir() for i in xy for j in xy] > [['.0', 'i', 'j'], ['.0', 'i', 'j'], ['.0', 'i', 'j'], ['.0', 'i', 'j']] > >>> class foo(): > ... xs = [1,2] > ... z5 = [dir() for i in xs for j in xs] > ... > Traceback (most recent call last): > File "", line 1, in > File "", line 3, in foo > File "", line 3, in > NameError: name 'xs' is not defined > >>> > > That's all I had learn so far, although not understand the design decision > behind it yet:-( > > --Jach Anyway, it "looks" weird. Isn't it? >>> xs = [5,6,7,8] >>> class foo(): ... xs = [1,2,3] ... z4 = [xs[i] for i in xs] ... >>> foo.z4 [6,7,8] xs in the "for" statement referenced to class variable xs and xs[i] in the body referenced to the global xs with i from locals. PS. Don't bother to reply. This is just for my own documentary:-) -- https://mail.python.org/mailman/listinfo/python-list
Re: Ask for help about class variable scope (Re: Why doesn't a dictionary work in classes?)
eryk sun at 2018/12/27 UTC+8 PM 6:58:33 wrote: > On 12/27/18, jf...@ms4.hinet.net wrote: > > > > I still don't get it. When I change it to using list comprehension, the > > problem is still there. (it now has no late-binding variable, right? :-) > > > class Too: > > ... XS = [15, 15, 15, 15] > > ... Z4 = [val for val in XS] > > ... Z5 = [XS[0] for val in XS] > > ... > > Traceback (most recent call last): > > File "", line 1, in > > File "", line 4, in Too > > File "", line 4, in > > NameError: name 'XS' is not defined > > > > The problem confuse me is that is XS a local variable of the list > > comprehension? > > XS is not a local variable in the scope of either comprehension. XS is > local to the class statement's scope. For each comprehension, an > iterator for the current object referenced by XS gets instantiated > (early binding) and passed as an argument to the comprehension scope. > If we disassemble the comprehension code, we find that this iterator > argument has the creatively illegal name ".0". (The bytecode > references it by its fast-locals-array index, not its weird name.) > > In the Z5 case, XS is a non-local variable (late binding) in the > loop-body expression (left-hand side) of the comprehension. That's > common for Python code. In every iteration of the loop, the > interpreter looks up the object referenced by the name "XS", which can > change at any time (e.g. by another thread). In Python document 4.2.2. Resolution of names, the last paragraph: "...A class definition is an executable statement that may use and define names. These references follow the normal rules for name resolution with an exception that unbound local variables are looked up in the global namespace. ...The scope of names defined in a class block is limited to the class block; it does not extend to the code blocks of methods – this includes comprehensions and generator expressions since they are implemented using a function scope". These statements reflect the following difference: >>> xy = [1,2] >>> [dir() for i in xy] [['.0', 'i'], ['.0', 'i']] >>> [xy[0] for i in xy] [1, 1] >>> class foo(): ... xs = [1,2] ... z4 = [dir() for i in xs] ... >>> foo().z4 [['.0', 'i'], ['.0', 'i']] >>> class foo(): ... xs = [1,2] ... z4 = [xs[0] for i in xs] ... Traceback (most recent call last): File "", line 1, in File "", line 3, in foo File "", line 3, in NameError: name 'xs' is not defined >>> and it goes further: >>> [dir() for i in xy for j in xy] [['.0', 'i', 'j'], ['.0', 'i', 'j'], ['.0', 'i', 'j'], ['.0', 'i', 'j']] >>> class foo(): ... xs = [1,2] ... z5 = [dir() for i in xs for j in xs] ... Traceback (most recent call last): File "", line 1, in File "", line 3, in foo File "", line 3, in NameError: name 'xs' is not defined >>> That's all I had learn so far, although not understand the design decision behind it yet:-( --Jach -- https://mail.python.org/mailman/listinfo/python-list
Re: Ask for help about class variable scope (Re: Why doesn't a dictionary work in classes?)
On Fri, Dec 28, 2018 at 8:47 AM eryk sun wrote: > > On 12/27/18, Chris Angelico wrote: > > > > 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. > > A generator expression is implemented internally as a generator > function that takes an iterator as its only parameter (named ".0") and > gets called immediately to get a generator object. There's some inline > bytecode in the defining scope that sets this up. > > A generator object has iterator methods (__iter__, __next__) and > close, send, and throw methods. Its code and execution state in > CPython uses a code object and a frame object: A generator expression is an expression that creates and then calls a function to create a generator object. This is exactly the same as any other generator function being called to create a generator object. Yes, the generator function and the generator object are very different beasts, and yes, they're both called "a generator", and yes, this is confusing. But it's the same whether it's a genexp or an explicit function. > Unlike a function object, a generator object is not a descriptor (i.e. > it has no __get__ method) that could in principle be bound as either a > class or instance method. Anyway, since the class doesn't exist yet, > trying to bind and call a method at this point can't work. This is correct. A genexp created at class scope would be approximately equivalent to a generator function called as "Foo.f()" not as "Foo().f()" - called on the class, not an instance of it. > This is straying off topic, but note that a consequence of late > binding is that super() can be broken by rebinding __class__: > > class C: > def f(self): > nonlocal __class__ > __class__ = None > super() > > >>> C().f() > Traceback (most recent call last): > File "", line 1, in > File "", line 5, in f > RuntimeError: super(): __class__ is not a type (NoneType) > > It's not a bug or design flaw; just an example of code shooting itself > in the foot by stepping on an informally reserved dunder name. Technically only the no-arg form of super() can be broken that way, because it's actually a bit of magic syntax that becomes "super(__class__, self)", except that it doesn't actually use "self" but "whatever the first argument to this function is". You can break it in an even simpler way: >>> class C: ... def f(): ... super() ... >>> C.f() Traceback (most recent call last): File "", line 1, in File "", line 3, in f RuntimeError: super(): no arguments "But Mum, I thought you said you wanted NO ARGUMENTS while you were out" ChrisA -- https://mail.python.org/mailman/listinfo/python-list
Re: Ask for help about class variable scope (Re: Why doesn't a dictionary work in classes?)
On 12/27/18, Chris Angelico wrote: > > 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. A generator expression is implemented internally as a generator function that takes an iterator as its only parameter (named ".0") and gets called immediately to get a generator object. There's some inline bytecode in the defining scope that sets this up. A generator object has iterator methods (__iter__, __next__) and close, send, and throw methods. Its code and execution state in CPython uses a code object and a frame object: >>> g = (c for c in 'spam') >>> g.gi_code.co_varnames ('.0', 'c') Initially it hasn't run, so there's no 'c' value yet: >>> sorted(g.gi_frame.f_locals) ['.0'] 'c' is defined after it executes up to the first yield: >>> next(g) 's' >>> sorted(g.gi_frame.f_locals) ['.0', 'c'] Unlike a function object, a generator object is not a descriptor (i.e. it has no __get__ method) that could in principle be bound as either a class or instance method. Anyway, since the class doesn't exist yet, trying to bind and call a method at this point can't work. In contrast generator functions are commonly used for methods that can access class attributes. But this is confusing matters since the class __dict__ (and certainly not the instance __dict__) that's used for attributes is not the locals() of the initial class statement execution. In other words, class attribute access is not a closure over the class statement scope. For methods, it depends on early binding of the bound object to a method's __self__ attribute, which is implicitly passed as the first argument to its __func__ function when the method is called. The execution locals of a class statement is a temporary namespace that gets copied when the class object is instantiated. For example: class C: exec_dict = locals() >>> C.s = 'spam' >>> sorted(C.__dict__) ['__dict__', '__doc__', '__module__', '__weakref__', 'exec_dict', 's'] The original locals(): >>> sorted(C.exec_dict) ['__module__', '__qualname__', 'exec_dict'] What could be done is for the compiler to introduce nonlocal free variables (like what's already done with __class__), and then capture the current value to the locals() dict after it's done executing. For example (a clumsy one; in practice it would be implicit, expanding on how __class__ is implemented): def make_Foo(): XS = None class Foo: nonlocal XS XS = [15] * 4 Z5 = sum(XS[i] for i in range(len(XS))) locals()['XS'] = XS return Foo >>> Foo = make_Foo() >>> Foo.Z5 60 >>> Foo.XS [15, 15, 15, 15] However, this would be confusing in general, since there's no way to keep the class attribute in sync with the cell variable. So a function that's called as a class method may see different values for XS and cls.XS. This is a bad idea. This is straying off topic, but note that a consequence of late binding is that super() can be broken by rebinding __class__: class C: def f(self): nonlocal __class__ __class__ = None super() >>> C().f() Traceback (most recent call last): File "", line 1, in File "", line 5, in f RuntimeError: super(): __class__ is not a type (NoneType) It's not a bug or design flaw; just an example of code shooting itself in the foot by stepping on an informally reserved dunder name. -- https://mail.python.org/mailman/listinfo/python-list
Re: Ask for help about class variable scope (Re: Why doesn't a dictionary work in classes?)
On Fri, Dec 28, 2018 at 3:31 AM Ian Kelly wrote: > > On Wed, Dec 26, 2018 at 11:21 PM Chris Angelico wrote: > > > > On Thu, Dec 27, 2018 at 1:56 PM 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
Re: Ask for help about class variable scope (Re: Why doesn't a dictionary work in classes?)
On Wed, Dec 26, 2018 at 11:21 PM Chris Angelico wrote: > > On Thu, Dec 27, 2018 at 1:56 PM 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. 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. -- https://mail.python.org/mailman/listinfo/python-list
Re: Ask for help about class variable scope (Re: Why doesn't a dictionary work in classes?)
On 12/27/18, jf...@ms4.hinet.net wrote: > > I still don't get it. When I change it to using list comprehension, the > problem is still there. (it now has no late-binding variable, right? :-) > class Too: > ... XS = [15, 15, 15, 15] > ... Z4 = [val for val in XS] > ... Z5 = [XS[0] for val in XS] > ... > Traceback (most recent call last): > File "", line 1, in > File "", line 4, in Too > File "", line 4, in > NameError: name 'XS' is not defined > > The problem confuse me is that is XS a local variable of the list > comprehension? XS is not a local variable in the scope of either comprehension. XS is local to the class statement's scope. For each comprehension, an iterator for the current object referenced by XS gets instantiated (early binding) and passed as an argument to the comprehension scope. If we disassemble the comprehension code, we find that this iterator argument has the creatively illegal name ".0". (The bytecode references it by its fast-locals-array index, not its weird name.) In the Z5 case, XS is a non-local variable (late binding) in the loop-body expression (left-hand side) of the comprehension. That's common for Python code. In every iteration of the loop, the interpreter looks up the object referenced by the name "XS", which can change at any time (e.g. by another thread). -- https://mail.python.org/mailman/listinfo/python-list
Re: Ask for help about class variable scope (Re: Why doesn't a dictionary work in classes?)
On 12/26/2018 9:53 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) The iterable passed in to the comprehension is XS. try: Z5 = sum(XS[i] for i in range(len(XS))) The iterable passed in to the comprehension function is range(len(XS)). XS is a class name, not a global or outer function local name, hence invisible to the inner function. except NameError: Z5 = None print(Foo.Z4, Foo.Z5) 60 None --Jach -- Terry Jan Reedy -- https://mail.python.org/mailman/listinfo/python-list
Re: Ask for help about class variable scope (Re: Why doesn't a dictionary work in classes?)
eryk sun於 2018年12月27日星期四 UTC+8下午2時31分58秒寫道: > On 12/26/18, 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 > > Maybe rewriting it with approximately equivalent inline code and > generator functions will clarify the difference: > > class Foo: > def genexpr1(iterable): > for val in iterable: > yield val > > def genexpr2(iterable): > for i in iterable: > yield XS[i] > > XS = [15, 15, 15, 15] > Z4 = sum(genexpr1(XS)) > try: > Z5 = sum(genexpr2(range(len(XS > except NameError: > Z5 = None > > del genexpr1, genexpr2 > > >>> print(Foo.Z4, Foo.Z5) > 60 None > > In both cases, an iterable is passed to the generator function. This > argument is evaluated in the calling scope (e.g. range(len(XS))). A > generator expression has a similar implementation, except it also > evaluates the iterator for the iterable to ensure an exception is > raised immediately in the defining scope if it's not iterable. For > example: > > >>> (x for x in 1) > Traceback (most recent call last): > File "", line 1, in > TypeError: 'int' object is not iterable > > genexpr1 is working with local variables only, but genexpr2 has a > non-local reference to variable XS, which we call late binding. In > this case, when the generator code executes the first pass of the loop > (whenever that is), it looks for XS in the global (module) scope and > builtins scope. It's not there, so a NameError is raised. > > With late-binding, the variable can get deleted or modified in the > source scope while the generator gets evaluated. For example: > > >>> x = 'spam' > >>> g = (x[i] for i in range(len(x))) > >>> next(g) > 's' > >>> del x > >>> next(g) > Traceback (most recent call last): > File "", line 1, in > File "", line 1, in > NameError: name 'x' is not defined > > >>> x = 'spam' > >>> g = (x[i] for i in range(len(x))) > >>> next(g) > 's' > >>> x = 'eggs' > >>> list(g) > ['g', 'g', 's'] I still don't get it. When I change it to using list comprehension, the problem is still there. (it now has no late-binding variable, right? :-) >>> class Too: ... XS = [15, 15, 15, 15] ... Z4 = [val for val in XS] ... Z5 = [XS[0] for val in XS] ... Traceback (most recent call last): File "", line 1, in File "", line 4, in Too File "", line 4, in NameError: name 'XS' is not defined >>> The problem confuse me is that is XS a local variable of the list comprehension? If it's then Z5 should work, if it's not then Z4 shouldn't work when it's written in generator expression. Or, things is much more complex than I thought:-( -- https://mail.python.org/mailman/listinfo/python-list
Re: Ask for help about class variable scope (Re: Why doesn't a dictionary work in classes?)
On 12/26/18, 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 Maybe rewriting it with approximately equivalent inline code and generator functions will clarify the difference: class Foo: def genexpr1(iterable): for val in iterable: yield val def genexpr2(iterable): for i in iterable: yield XS[i] XS = [15, 15, 15, 15] Z4 = sum(genexpr1(XS)) try: Z5 = sum(genexpr2(range(len(XS except NameError: Z5 = None del genexpr1, genexpr2 >>> print(Foo.Z4, Foo.Z5) 60 None In both cases, an iterable is passed to the generator function. This argument is evaluated in the calling scope (e.g. range(len(XS))). A generator expression has a similar implementation, except it also evaluates the iterator for the iterable to ensure an exception is raised immediately in the defining scope if it's not iterable. For example: >>> (x for x in 1) Traceback (most recent call last): File "", line 1, in TypeError: 'int' object is not iterable genexpr1 is working with local variables only, but genexpr2 has a non-local reference to variable XS, which we call late binding. In this case, when the generator code executes the first pass of the loop (whenever that is), it looks for XS in the global (module) scope and builtins scope. It's not there, so a NameError is raised. With late-binding, the variable can get deleted or modified in the source scope while the generator gets evaluated. For example: >>> x = 'spam' >>> g = (x[i] for i in range(len(x))) >>> next(g) 's' >>> del x >>> next(g) Traceback (most recent call last): File "", line 1, in File "", line 1, in NameError: name 'x' is not defined >>> x = 'spam' >>> g = (x[i] for i in range(len(x))) >>> next(g) 's' >>> x = 'eggs' >>> list(g) ['g', 'g', 's'] -- https://mail.python.org/mailman/listinfo/python-list
Re: Ask for help about class variable scope (Re: Why doesn't a dictionary work in classes?)
On Thu, Dec 27, 2018 at 1:56 PM 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. ChrisA -- https://mail.python.org/mailman/listinfo/python-list
Re: Ask for help about class variable scope (Re: Why doesn't a dictionary work in classes?)
greetings, 1) Z4 = sum(val for val in XS) is same as Z4 = sum(XS) 2) class Foo() can also ne written as class Foo: 3) in Foo.x you are using the class just to assoxiate some variables with a name. what is the purpose of tge script / what are you trying to do? Abdur-Rahmaan Janhangeer http://www.pythonmembers.club | https://github.com/Abdur-rahmaanJ Mauritius -- https://mail.python.org/mailman/listinfo/python-list
Ask for help about class variable scope (Re: Why doesn't a dictionary work in classes?)
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 --Jach -- https://mail.python.org/mailman/listinfo/python-list