Re: [Python-Dev] Unbound locals in class scopes

Mon, 22 Jun 2015 00:16:55 -0700

On Mon, Jun 22, 2015 at 3:03 AM, Nick Coghlan <[email protected]> wrote:
> On 22 June 2015 at 08:46, Ivan Levkivskyi <[email protected]> wrote:> >> >> > On 21 June 2015 at 22:05, Guido van Rossum <[email protected]> wrote:> >>> >> On Sun, Jun 21, 2015 at 6:22 PM, Ivan Levkivskyi <[email protected]>> >> wrote:> >>>> >>> It is still not clear whether Guido's comment still stands for not> >>> raising an UnboundLocalError in class definitions but using globals> instead.> >>> >>> >> Can you phrase this in the form of an example, showing what it currently> >> does and what you think it should do, instead?> >>> >> > Here is an example:> >> > x = "xtop"> > y = "ytop"> > def func():> >     x = "xlocal"> >     y = "ylocal"> >     class C:> >         print(x)> >         print(y)> >         y = 1> > func()> >> > prints> >> > xlocal> > ytop> >> > Intuitively, one might think that it should raise UnboundLocalError or> print> > ylocal instead of ytop.> > This question was discussed 13 years ago and then you said that this> lookup> > in globals> > is an intentional behavior.> >> > This behavior is not documented, and I started an issue on bug tracker> > about documenting it.> > Then, Eric proposed to ask you again, whether this is still an> intentional> > behavior.>> Diving into some bytecode details:>In particular, the bytecode for C is:>>> dis.dis(func.__code__.co_consts[3])  6           0 LOAD_NAME                0 (__name__)              3 STORE_NAME               1 (__module__)              6 LOAD_CONST               0 ('func.<locals>.C')              9 STORE_NAME               2 (__qualname__)  7          12 LOAD_NAME                3 (print)             15 LOAD_CLASSDEREF          0 (x)             18 CALL_FUNCTION            1 (1 positional, 0 keyword pair)             21 POP_TOP  8          22 LOAD_NAME                3 (print)             25 LOAD_NAME                4 (y)             28 CALL_FUNCTION            1 (1 positional, 0 keyword pair)             31 POP_TOP  9          32 LOAD_CONST               1 (1)             35 STORE_NAME               4 (y)             38 LOAD_CONST               2 (None)             41 RETURN_VALUE>>>> We added LOAD_CLASSDEREF> (https://docs.python.org/3/library/dis.html#opcode-LOAD_CLASSDEREF) a> while back to account for the fact that __prepare__ may inject locals> into a class body that the compiler doesn't know about. Unlike> LOAD_DEREF, LOAD_CLASSDEREF checks the locals before it checks the> closure cell.>> However, neither LOAD_CLASSDEREF *nor* LOAD_DEREF is used for names> that are *assigned* in the class body - those get flagged as local> variables, so we end up emitting LOAD_NAME for them, and hence ignore> any nonlocal variables with that name. If a module global or builtin> exists, we'll find that, otherwise we'll throw NameError.>> With nested_scopes having been the default since 2.2, and accounting> for the fact that folks *do* write code like "name = name" at class> scope and expect it to "do the right thing", it seems reasonable to me> to just make this work properly, rather than having to explain why it> doesn't work as one might expected based on the behaviour of module> level class definitions and other references to nonlocal variables> from a class body.>But what *is* the correct behavior? I suspect people's intuitions differ.If you think of this as similar to function scopes you're likely to bewrong.Also, since classes inside functions are commonly used in unit tests (atleast mine :-), I worry that *any* changes in this behavior might breakworking code (no matter how much that "working" could be considered anaccident, it's still going to be a bear to debug if this happens to you).-- --Guido van Rossum (python.org/~guido)
_______________________________________________Python-Dev mailing list[email protected]https://mail.python.org/mailman/listinfo/python-devUnsubscribe:https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com

Reply via email to