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