homepage

This issue tracker has been migrated to GitHub , and is currently read-only.
For more information, see the GitHub FAQs in the Python's Developer Guide.

classification
Title: Incorrect (misleading) statement in the execution model documentation
Type: enhancement Stage: resolved
Components: Documentation Versions: Python 3.6, Python 3.4, Python 3.5
process
Status: closed Resolution: fixed
Dependencies: Superseder:
Assigned To: docs@python Nosy List: abacabadabacaba, arigo, docs@python, eric.snow, levkivskyi, ncoghlan, r.david.murray, rhettinger
Priority: normal Keywords: patch

Created on 2015年05月05日 20:51 by levkivskyi, last changed 2022年04月11日 14:58 by admin. This issue is now closed.

Files
File name Uploaded Description Edit
classdoc.patch levkivskyi, 2015年05月15日 08:44 Imptoved wording for docs on execution model (class statement) review
classdoc_v2.patch levkivskyi, 2015年06月19日 22:50 Made changes sugested by Eric review
classdoc-v3.patch levkivskyi, 2015年06月20日 13:55 A bit more extensive patch; main improvment is separating doc into subsections review
classdoc-v4.patch levkivskyi, 2015年06月21日 13:57 Comments of Nick and Eric are taken into account. review
Messages (18)
msg242619 - (view) Author: Ivan Levkivskyi (levkivskyi) * (Python committer) Date: 2015年05月05日 20:51
The documentation on execution model https://docs.python.org/3/reference/executionmodel.html contains the statement
"""
A class definition is an executable statement that may use and define names. These references follow the normal rules for name resolution. The namespace of the class definition becomes the attribute dictionary of the class. Names defined at the class scope are not visible in methods.
"""
However, the following code (taken from http://lackingrhoticity.blogspot.ch/2008/08/4-python-variable-binding-oddities.html):
x = "xtop"
y = "ytop"
def func():
 x = "xlocal"
 y = "ylocal"
 class C:
 print(x)
 print(y)
 y = 1
func()
prints
xlocal
ytop
In case of "normal rules for name resolution" it should rise UnboundLocalError.
I suggest replacing the mentioned statement with the following:
"""
A class definition is an executable statement that may use and define names. Free variables follow the normal rules for name resolution, bound variables are looked up in the global namespace. The namespace of the class definition becomes the attribute dictionary of the class. Names defined at the class scope are not visible in methods.
"""
or a similar one.
msg243258 - (view) Author: Ivan Levkivskyi (levkivskyi) * (Python committer) Date: 2015年05月15日 08:44
Since no one proposed alternative ideas, I am submitting my proposal as a patch, with the following wording:
"""
A class definition is an executable statement that may use and define names. Free variables follow the normal rules for name resolution, while unbound local variables are looked up in the global namespace. The namespace of the class definition becomes the attribute dictionary of the class. Names defined at the class scope are not visible in methods
"""
msg245514 - (view) Author: Ivan Levkivskyi (levkivskyi) * (Python committer) Date: 2015年06月19日 19:22
Should I invite someone to review the patch or just wait? How the things are organized here?
msg245517 - (view) Author: R. David Murray (r.david.murray) * (Python committer) Date: 2015年06月19日 19:46
In this particular case, just wait (now that you have pinged the issue). Raymond is the most likely person to figure out how to phrase this better, but it isn't obvious what the best way to explain this is. I don't think your explanation is exactly correct, but I don't know enough about how class name resolution is implemented to explain what's wrong with it, I just know it doesn't feel quite right :) (Of course, I might be wrong.)
Ping the issue again in a few weeks if there is no action.
msg245524 - (view) Author: Eric Snow (eric.snow) * (Python committer) Date: 2015年06月19日 19:58
I've left a review. That said, we need to be sure this behavior is intentional. The fact that it skips the "nonlocal" scope(s) smells like a bug to me.
msg245533 - (view) Author: Ivan Levkivskyi (levkivskyi) * (Python committer) Date: 2015年06月19日 22:50
Eric, thank you for the review. I have incorporated proposed changes in second version of the patch.
Concerning the question whether it is a bug, it also smells like a bug to me, but Guido said 13 years ago that this should not be changed: https://mail.python.org/pipermail/python-dev/2002-April/023428.html and it stayed like this since then. However, things changed a bit in Python 3.4 with the introduction of the LOAD_CLASSDEREF opcode. Perhaps, we should ask Guido again :) What do you think?
msg245535 - (view) Author: Eric Snow (eric.snow) * (Python committer) Date: 2015年06月19日 23:18
I expect you'll get the same response, especially given potential (though slight) chance for backward-compatibility issues. What I find curious is Guido's reference to "the rule that class bodies don't play the nested
scopes game" (and his subsequent explanation). Is there something about that in the language reference? If so, the patch should be updated to link to that section. If not then it should be added to the language reference.
That said, it wouldn't hurt to ask on python-dev, particularly in light of that new opcode.
msg245545 - (view) Author: Alyssa Coghlan (ncoghlan) * (Python committer) Date: 2015年06月20日 07:02
The "normal rules for name resolution" reference here is referring to the name lookup rules as they existed prior to the introduction of lexical scoping for functions. It's a dated way of describing it, as the current behaviour of functions has now been around long enough that a lot of folks will consider *that* normal, and the module, class and exec scoping rules to be the unusual case (as levkivskyi has here).
However, I've spent far too many hours staring at CPython compiler internals to be able to suggest a helpful rewording that will make sense to folks that *haven't* done that, so I'll instead provide the relevant background info to see if others can come up with a concise rewording of the reference docs :)
Prior to Python 2.1, Python didn't have closure support, and hence nested functions and classes couldn't see variables in outer scopes at all - they could see their local scope, the module globals, and the builtins. That changed with the introduction of nested scopes as a __future__ import in Python 2.1 and the default behaviour in 2.2: https://www.python.org/dev/peps/pep-0227/
As a result of that change, the compiler now keeps track of "function locals" at compile time, and *emits different code for references to them*. Where early versions of CPython only had LOAD_NAME and LOAD_GLOBAL in the bytecode, these days we now also have LOAD_FAST (function local), LOAD_CLOSURE (function local referenced as a nonlocal), LOAD_DEREF (function nonlocal) and LOAD_CLASSDEREF (class nonlocal). The latter four opcodes will *only* be emitted in a function body - they'll never be emitted for module level code (include the bodies of module level class definitions). If you attempt to reference a function local before a value has been assigned, you'll get UnboundLocalError rather than NameError.
The name lookup rules used for execution of class bodies are thus the same ones used for the exec() builtin with two namespace arguments: there is a local namespace where name assignments happen, and name lookups check the local, global and builtin namespaces in that order. The code is executed line by line, so if a name is referenced before it has been assigned locally, then it may find a global or builtin of that name. Classes that are defined inside a function may refer to lexically scoped local variables from the class body, but class variables are not themselves visible to function definitions nested inside a class scope (i.e. method definitions).
These rules are also used for module level execution and exec() with a single namespace argument, except that the local namespace and the global namespace refer to the same namespace.
msg245548 - (view) Author: Ivan Levkivskyi (levkivskyi) * (Python committer) Date: 2015年06月20日 07:14
Eric, the "rule" that classes don't play the nested scopes game is explained at beginning of the same section, but the explanation is "one sided" it only explains that names defined in classes are not visible inside functions.
Nick, thank you for the thorough explanation. I will try to improve the wording. It looks like a bit more substantial changes are needed.
msg245554 - (view) Author: Armin Rigo (arigo) * (Python committer) Date: 2015年06月20日 08:24
Related to http://bugs.python.org/issue19979 and others mentioned there.
msg245562 - (view) Author: Ivan Levkivskyi (levkivskyi) * (Python committer) Date: 2015年06月20日 13:55
Eric, I have submitted a new version of the patch. Could you please make a review? Nick, it will be interesting to hear your opinion too.
I tried to follow such rules:
1. Explanation should be succinct yet clear
2. It should tell as less as possible about implementation details
3. Minimize necessary changes
It turns out that these goals could be achieved by 
a) simply reshuffling and structuring the existing text to separate the exceptions (classes, etc.) from the general case;
and
b) adding some minor clarifications.
Armin, thank you for the link. It looks like this is a really old discussion.
PS: Unfortunately, the diff after reshuffling of the text looks big and cumbersome, in fact the changes are minimal.
msg245596 - (view) Author: Ivan Levkivskyi (levkivskyi) * (Python committer) Date: 2015年06月21日 13:57
Nick, thank you for a review, I have made a new patch with all the previous comments taken into account.
msg245697 - (view) Author: Ivan Levkivskyi (levkivskyi) * (Python committer) Date: 2015年06月23日 19:09
It looks like on python-dev (http://www.mail-archive.com/python-dev@python.org/msg88256.html) there is an agreement that this behavior should not be changed (at least not in the nearest future). If there are no more comments/suggestions, then maybe one could accept the latest patch?
msg246031 - (view) Author: Ivan Levkivskyi (levkivskyi) * (Python committer) Date: 2015年07月01日 08:41
What holds the patch now? Should I do something or just wait?
msg247800 - (view) Author: Ivan Levkivskyi (levkivskyi) * (Python committer) Date: 2015年08月01日 08:14
I am sorry but I still don't get how things are organized here, so pinging this up. What is the next step? Should I wait for another review?
msg247938 - (view) Author: R. David Murray (r.david.murray) * (Python committer) Date: 2015年08月03日 17:03
Your ping after a month is very appropriate. It looks like yes, this is waiting for another review. Based on the fact that the previous patches were reviewed by core devs and you have responded, I'm moving it to 'commit review', but I haven't looked at the patch myself.
msg248039 - (view) Author: Alyssa Coghlan (ncoghlan) * (Python committer) Date: 2015年08月05日 13:43
I merged Ivan's latest patch to 3.4/3.5/default. We're unlikely to ever be able to make these docs completely intuitive (as name resolution is genuinely complex), but Ivan's revisions at least mean we're no longer assuming readers know how the name resolution worked prior to the introduction of lexical scoping, and a couple of tricky cases now have inline examples.
I also noticed an existing paragraph in the docs that *I* didn't understand, and filed issue #24796 to cover that. I'm not sure if we should just delete the paragraph, or if we accidentally dropped a compile time error check that didn't have any tests to ensure we were detecting the problem.
msg248045 - (view) Author: Alyssa Coghlan (ncoghlan) * (Python committer) Date: 2015年08月05日 14:55
The issue tracker was having issues and didn't automatically register the commits. Links:
3.4: https://hg.python.org/cpython/rev/94e215a5e24b
3.5: https://hg.python.org/cpython/rev/5e4d21311772
default: https://hg.python.org/cpython/rev/e75881393cf2 
History
Date User Action Args
2022年04月11日 14:58:16adminsetgithub: 68317
2015年08月05日 14:55:27ncoghlansetmessages: + msg248045
2015年08月05日 14:53:17ncoghlansetmessages: - msg248043
2015年08月05日 14:51:51ncoghlansetmessages: + msg248043
2015年08月05日 14:47:23ncoghlansetstatus: open -> closed
type: behavior -> enhancement
messages: + msg248039

resolution: fixed
stage: commit review -> resolved
2015年08月03日 17:03:08r.david.murraysetstage: commit review
messages: + msg247938
versions: + Python 3.6
2015年08月01日 08:14:56levkivskyisetmessages: + msg247800
2015年07月01日 08:41:04levkivskyisetmessages: + msg246031
2015年06月23日 19:09:32levkivskyisetmessages: + msg245697
2015年06月22日 18:56:26abacabadabacabasetnosy: + abacabadabacaba
2015年06月21日 13:57:11levkivskyisetfiles: + classdoc-v4.patch

messages: + msg245596
2015年06月20日 13:55:42levkivskyisetfiles: + classdoc-v3.patch

messages: + msg245562
2015年06月20日 08:24:30arigosetnosy: + arigo
messages: + msg245554
2015年06月20日 07:14:09levkivskyisetmessages: + msg245548
2015年06月20日 07:02:57ncoghlansetmessages: + msg245545
2015年06月19日 23:18:56eric.snowsetnosy: + ncoghlan
messages: + msg245535
2015年06月19日 22:50:16levkivskyisetfiles: + classdoc_v2.patch

messages: + msg245533
2015年06月19日 19:58:54eric.snowsetnosy: + eric.snow
messages: + msg245524
2015年06月19日 19:47:00r.david.murraysetnosy: + r.david.murray
messages: + msg245517
2015年06月19日 19:22:08levkivskyisetmessages: + msg245514
2015年05月15日 08:44:09levkivskyisetfiles: + classdoc.patch
keywords: + patch
messages: + msg243258
2015年05月08日 20:51:20rhettingersetnosy: + rhettinger
2015年05月05日 20:51:59levkivskyicreate

AltStyle によって変換されたページ (->オリジナル) /