__doc__ behavior in class definitions

Hello Python-Dev, My name is Martin Maly and I am a developer at Microsoft, working on the IronPython project with Jim Hugunin. I am spending lot of time making IronPython compatible with Python to the extent possible. I came across a case which I am not sure if by design or a bug in Python (Python 2.4.1 (#65, Mar 30 2005, 09:13:57)). Consider following Python module: # module begin "module doc" class c: print __doc__ __doc__ = "class doc" (1) print __doc__ print c.__doc__ # module end When ran, it prints: module doc class doc class doc Based on the binding rules described in the Python documentation, I would expect the code to throw because binding created on the line (1) is local to the class block and all the other __doc__ uses should reference that binding. Apparently, it is not the case. Is this bug in Python or are __doc__ strings in classes subject to some additional rules? Thanks Martin

Martin Maly wrote:
I came across a case which I am not sure if by design or a bug in Python (Python 2.4.1 (#65, Mar 30 2005, 09:13:57)). Consider following Python module:
# module begin "module doc"
class c: print __doc__ __doc__ = "class doc" (1) print __doc__
print c.__doc__ # module end
When ran, it prints:
module doc class doc class doc
Based on the binding rules described in the Python documentation, I would expect the code to throw because binding created on the line (1) is local to the class block and all the other __doc__ uses should reference that binding. Apparently, it is not the case.
Is this bug in Python or are __doc__ strings in classes subject to some additional rules?
it's not limited to __doc__ strings, or, for that matter, to attributes: spam = "spam" class c: print spam spam = "bacon" print spam print len(spam) def len(self): return 10 print c.spam the language reference uses the term "local scope" for both class and def-statements, but it's not really the same thing. the former is more like a temporary extra global scope with a (class, global) search path, names are resolved when they are found (just as in the global scope); there's no preprocessing step. for additional class issues, see the "Discussion" in the nested scopes PEP: http://www.python.org/peps/pep-0227.html hope this helps! </F>

Martin Maly wrote:
Hello Python-Dev,
My name is Martin Maly and I am a developer at Microsoft, working on the IronPython project with Jim Hugunin. I am spending lot of time making IronPython compatible with Python to the extent possible.
I came across a case which I am not sure if by design or a bug in Python (Python 2.4.1 (#65, Mar 30 2005, 09:13:57)). Consider following Python module:
# module begin "module doc"
class c: print __doc__ __doc__ = "class doc" (1) print __doc__
print c.__doc__ # module end
When ran, it prints:
module doc class doc class doc
Based on the binding rules described in the Python documentation, I would expect the code to throw because binding created on the line (1) is local to the class block and all the other __doc__ uses should reference that binding. Apparently, it is not the case.
Is this bug in Python or are __doc__ strings in classes subject to some additional rules?
Well, it's nothing to do with __doc__, as the following example shows: crud = "module crud" class c: print crud crud = "class crud" print crud print c.crud As you might by now expect, this outputs module crud class crud class crud Clearly the rules for class scopes aren't quite the same as those for function scopes, as the module crud = "module crud" def f(): print crud crud = "function crud" print crud f() does indeed raise an UnboundLocalError exception. I'm not enough of a language lawyer to determine exactly why this is, but it's clear that class variables aren't scoped in the same way as function locals. regards Steve -- Steve Holden +44 150 684 7255 +1 800 494 3119 Holden Web LLC www.holdenweb.com PyCon TX 2006 www.python.org/pycon/

On Fri, Oct 07, 2005 at 12:15:04PM -0700, Martin Maly wrote:
Hello Python-Dev,
My name is Martin Maly and I am a developer at Microsoft, working on the IronPython project with Jim Hugunin. I am spending lot of time making IronPython compatible with Python to the extent possible.
I came across a case which I am not sure if by design or a bug in Python (Python 2.4.1 (#65, Mar 30 2005, 09:13:57)). Consider following Python module:
# module begin "module doc"
class c: print __doc__ __doc__ = "class doc" (1) print __doc__
[snip]
Based on the binding rules described in the Python documentation, I would expect the code to throw because binding created on the line (1) is local to the class block and all the other __doc__ uses should reference that binding. Apparently, it is not the case.
Is this bug in Python or are __doc__ strings in classes subject to some additional rules?
Classes behave just like you would expect them to, for proper variations of what to expect *wink*. The class body is evaluated first with the same local/global name lookups as would happen inside another scope (e.g. a function). The results of that evaluation are then passed to the class constructor as a dict. The __new__ method of metaclasses and the less used 'new' module highlight the final step that turns a bucket of stuff in a namespace into a class.
import new A = new.classobj('w00t', (object,), {'__doc__':"no help at all", 'myself':lambda x:x}) a = A() a.myself() <__main__.w00t object at 0xb7bc32cc> a <__main__.w00t object at 0xb7bc32cc> help(a) Help on w00t in module __main__ object:
class w00t(__builtin__.object) | no help at all | | Methods defined here: | | lambdax |
Hope that helps, -jackdied

Martin, These two cases generate different bytecode. def foo(): # foo.func_code.co_flags == 0x43 print x # LOAD_FAST 0 x = 3 class Foo: # <code object>.co_flags == 0x40 print x # LOAD_NAME 'x' x = 3 In functions, local variables are just numbered slots. (co_flags bits 1 and 2 indicate this.) The LOAD_FAST opcode is used. If the slot is empty, LOAD_FAST throws. In other code, the local variables are actually stored in a dictionary. LOAD_NAME is used. This does a locals dictionary lookup; failing that, it falls back on the globals dictionary; and failing that, it falls back on builtins. Why the discrepancy? Beats me. I would definitely implement what CPython does up to this point, if that's your question. Btw, functions that use 'exec' are in their own category way out there: def foo2(): # foo2.func_code.co_flags == 0x42 print x # LOAD_NAME 'x' exec "x=3" # don't ever do this, it screws everything up print x Pretty weird. Jython seems to implement this. -j
participants (5)
-
Fredrik Lundh
-
Jack Diederich
-
Jason Orendorff
-
Martin Maly
-
Steve Holden