Ask for help about class variable scope (Re: Why doesn't a dictionary work in classes?)

jfong at ms4.hinet.net jfong at ms4.hinet.net
Fri Dec 28 21:39:29 EST 2018


jf... at 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, jfong at ms4.hinet.net <jfong at 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 "<stdin>", line 1, in <module>
> > >   File "<stdin>", line 4, in Too
> > >   File "<stdin>", line 4, in <listcomp>
> > > 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 "<stdin>", line 1, in <module>
>   File "<stdin>", line 3, in foo
>   File "<stdin>", line 3, in <listcomp>
> 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 "<stdin>", line 1, in <module>
>   File "<stdin>", line 3, in foo
>   File "<stdin>", line 3, in <listcomp>
> 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:-)


More information about the Python-list mailing list