[Python-bugs-list] [ python-Bugs-532860 ] NameError assigning to class in a func

noreply@sourceforge.net noreply@sourceforge.net
Mon, 22 Apr 2002 11:43:12 -0700


Bugs item #532860, was opened at 2002-03-21 01:27
You can respond by visiting: 
http://sourceforge.net/tracker/?func=detail&atid=105470&aid=532860&group_id=5470

Category: Python Interpreter Core
Group: Python 2.2
>Status: Closed
Resolution: Wont Fix
Priority: 5
Submitted By: Andrew Bennetts (spiv)
Assigned to: Jeremy Hylton (jhylton)
Summary: NameError assigning to class in a func

Initial Comment:
This fails with a NameError:

def f(x)
    class Private:
        x = x
    return Private
f(17)

But this works:

def f(x):
    y = x
    class Private:
        x = y
    return Private
f(17)

But this fails:

def f(x):
    y = x
    class Private:
        y = y
    return Private
f(17)

See also the newsgroup thread:
http://groups.google.com/groups?hl=en&ie=ISO-8859-1&oe=ISO-8859-1&threadm=Xns

(All tested on Python 2.2 on Win2k)



----------------------------------------------------------------------

>Comment By: Jeremy Hylton (jhylton)
Date: 2002-04-22 18:43

Message:
Logged In: YES 
user_id=31392

Indeed, after conversation with GvR, we are in agreement 
that it would break too much old code to "fix" this.  Just 
don't write code that abuses the wart at the module level, 
and you'll never feel its a bug when nested inside a 
function <0.1 wink>.


----------------------------------------------------------------------

Comment By: Jeremy Hylton (jhylton)
Date: 2002-04-22 17:25

Message:
Logged In: YES 
user_id=31392

The behavior bugs me too, but I don't expect it will get 
fixed because of the need for backwards compatibility.  The 
local namespace for classes, modules, and functions that 
contain exec or import * are searched using the LOAD_NAME 
opcode.  This opcode implements the old locals, globals, 
builtin search for a name using dict lookup.  If the dict 
lookup fails at any level, the next level up is searched.  
This means an unbound local error will never occur in a 
class block, because the dict lookup just returns NULL and 
the search proceeds to globals.

If anything, the bug is the was "x=x" behaves at the class 
level, but I'm loathe to change it.  It will probably break 
existing code and will require substantial implementation 
effort (I think) because class namespaces aren't 
implemented using the same technique as a function 
namespace.

I'd rather document the existing wart and live with it.  In 
particular, I might document it with the following weasle 
words: "The result of reference an unbound local name in a 
class block is undefined."


----------------------------------------------------------------------

Comment By: Andrew Bennetts (spiv)
Date: 2002-04-22 09:31

Message:
Logged In: YES 
user_id=50945

Apologies for re-opening the bug.

This behaviour still seems like a bug to me, because while
this dies:

>>> def f(x):
...     class Private:
...         x = x
...     return Private
... 
>>> f(17)
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
  File "<stdin>", line 2, in f
  File "<stdin>", line 3, in Private
NameError: name 'x' is not defined

This works:

>>> x = 1 
>>> class C:
...     x = x
... 
>>> C()
<__main__.C instance at 0x806aeac>

Actually, having the global "x = 1" also makes the first
case work.

This seems inconsistent enough to me to warrant it being
called a bug, regardless of the underlying implementation
details (which I know little of).  I'd expect it work in
both cases, or neither case.

Feel free to close the bug again if you disagree :)

It's quite easy to work around, so I'm not worried greatly
by it.
(workaround:
def f(x):
    class Private:
         pass
    Private.x = x
    return Private
)


----------------------------------------------------------------------

Comment By: Jeremy Hylton (jhylton)
Date: 2002-04-19 16:39

Message:
Logged In: YES 
user_id=31392

This is actually working as intended, although the reference
manual no longer describes this case at all.  It has been a
long standing "feature" of Python that module and class
blocks use the LOAD_NAME opcode, which has weird scoping
rules.

The documentation should be updated to describe the cases in
which LOAD_NAME is used and its behavior.  (It checks
locals, globals, builtins in that order, and never raises a
NameError unless the name isn't found in any of those
namespaces.  In particular, an unbound local is simply
ignored.)

I don't actually know what these rules are used.  Guido--
should we get rid of LOAD_NAME?


----------------------------------------------------------------------

You can respond by visiting: 
http://sourceforge.net/tracker/?func=detail&atid=105470&aid=532860&group_id=5470