views:

139

answers:

3

Hi all!

The following works Ok, i.e. it doesn't give any errors:

def foo(arg):
    class Nested(object):
        x = arg

foo('hello')

But the following throws an exception:

def foo(arg):
    class Nested(object):
        arg = arg # note that names are the same

foo('hello')

Traceback:

Traceback (most recent call last):
  File "test.py", line 6, in <module>
    foo('hello')
  File "test.py", line 3, in foo
    class Nested(object):
  File "test.py", line 4, in Nested
    arg = arg
NameError: name 'arg' is not defined

I can't understand the reason of such behavior. Could anybody explain?

+1  A: 

The arg property shadows the arg function argument (inner scoping)

def foo(arg):
    class Nested(object):
        arg = arg # you try to read the `arg` property which isn't initialized


You get the same error if you type i = i in the interpreter window without having initialized the i variable.

Nick D
+1: This will also work if you had "arg = 12", but in this case, the arg variable passed in and the arg variable belonging to the Nested class are 2 separate variables
Steg
This doesn't quite explain why x = arg works then, it should fail for the same reason, but it doesn't. The real reason is as Daniel pointed out, that Python assumes its local because it is being assigned to.
Andre Miller
Try to insert 'x = arg' just before 'arg = arg' and you'll get the same error on that new line. At that moment foo's arg is not yet shadowed. Isn't it?
nailxx
@Andre: I believe that this is because the class is defined inside the function, meaning its scope includes that of the function, hence "x = arg" initialises Nested.x to the value passed into the function. You can check this by adding a local variable to the function and initialising a class member to that variable
Steg
nail.xx, the argument 'arg' will be shadowed as soon as the property 'arg' is created.
Nick D
+1  A: 

If you try and assign to a variable within a function, Python assumes that variable is local to that function. So by trying to assign arg to the value of itself, you are implicitly declaring it as a local variable.

Daniel Roseman
+1  A: 

It is due to Python's scoping rules:

def foo(arg): # (1)
    class Nested(object):
        arg = arg # (2)

(2) defines a new 'arg' name in the class' namespace, which opaques the value of the other 'arg' in the outer namespace (1).

However, (2) is unnecessary and the following is completely valid:

def foo(arg):
    class Nested(object):
        def message(self):
            print arg
    return Nested()

nested = foo('hello')
nested.message()

(prints hello)

martin
But in (2) arg in class' namespace is not yet defined at the moment arg from (1) is used. Try to insert 'x = arg' just before (2) and you'll get the same error on that new line. At that moment arg is definitely not yet defined at class level.So IMO the problem is somewhere else.
nailxx
The problem persists because of python's scoping rules (have a look here: http://docs.python.org/tutorial/classes.html#python-scopes-and-name-spaces). 'arg' being on the left side of an assignment shadows the name for the whole block, even for lines before.
martin