Weird behavior with lexical scope

Terry Reedy tjreedy at udel.edu
Thu Nov 6 17:32:12 EST 2008


saju.pillai at gmail.com wrote:
> On Nov 6, 9:57 pm, mrstevegross <mrstevegr... at gmail.com> wrote:
>> I ran into a weird behavior with lexical scope in Python. I'm hoping
>> someone on this forum can explain it to me.
>>
>> Here's the situation: I have an Outer class. In the Outer class, I
>> define a nested class 'Inner' with a simple constructor. Outer's
>> constructor creates an instance of Inner. The code looks like this:
>>
>> =========
>> class Outer:
>>   class Inner:
>>     def __init__(self):
>>       pass
>>   def __init__ (self):
>>     a = Inner()
>> Outer()
>> =========
>>
>> However, the above code doesn't work. The creation of Inner() fails.
>> The error message looks like this:
>>
>>   File "/tmp/foo.py", line 12, in <module>
>>     Outer()
>>   File "/tmp/foo.py", line 10, in __init__
>>     a = Inner()
>> NameError: global name 'Inner' is not defined
>>
>> This surprises me! Since the construction of Inner takes place within
>> the lexical scope 'Outer', I assumed the interpreter would search the
>> Outer scope and find the 'Inner' symbol. But it doesn't! If I change:
>>   a = Inner()
>> to
>>   a = Outer.Inner()
>>
>> it works fine, though.

So do that.

> AFAIK, when 'Outer.__init__' executes, 'Inner' is first searched for
> within 'Outer.__init__()'s local namespace. Since 'Inner' is defined
> outside the function namespace, the search will fail. Python then
> looks at the module level namespace - where Inner is again not defined
> (only 'Outer' is available in the module namespace), the final search
> will be in the interpreter global namespace which will fail too. When

Interpreter global namespace == builtins

> you change your code from 'Inner' to 'Outer.Inner', the module level
> namespace search will match ( or atleast that's how i think it should
> all work :) )

Correct

> Try this ..

Why?

> class Outer:
>    def __init__(self):
>       class Inner:
>          def __init__(self): pass
>       a = Inner()

This create a duplicate Inner class object for every instance of Outer, 
which is almost certainly not what the OP wants.

> Outer()
> 
> This should work, because the Outer.__init__ namespace (first
> namespace being searched) has Inner defined within it

tjr




More information about the Python-list mailing list