Instance of inherited nested class in outer class not allowed?

M

mrstephengross

I've got an interesting problem with my class hierarchy. I have an
outer class, in which two nested classes are defined:

class Outer:
class Parent:
def __init__ (self):
print "parent!"
class Child(Parent):
def __init__ (self):
Outer.Parent.__init__(self)
foo = Child()

Note that the second nested class (Outer.Child) inherits from the
first nested class (Outer.Parent). When I run the above code, python
reports a name error:

Traceback (most recent call last):
File "./temp.py", line 3, in ?
class Outer:
File "./temp.py", line 13, in Outer
foo = Child()
File "./temp.py", line 11, in __init__
Outer.Parent.__init__(self)
NameError: global name 'Outer' is not defined

Apparently, python doesn't like having an instance of a derived nested
class present in the outer class. Interestingly enough, if I change
the foo variable to an instance of the parent class:

foo = Parent()

everything is hunky-dory. Is there some syntax rule I'm breaking here?

Thanks!
--Steve
 
D

Diez B. Roggisch

mrstephengross said:
I've got an interesting problem with my class hierarchy. I have an
outer class, in which two nested classes are defined:

class Outer:
class Parent:
def __init__ (self):
print "parent!"
class Child(Parent):
def __init__ (self):
Outer.Parent.__init__(self)
foo = Child()

Note that the second nested class (Outer.Child) inherits from the
first nested class (Outer.Parent). When I run the above code, python
reports a name error:

Traceback (most recent call last):
File "./temp.py", line 3, in ?
class Outer:
File "./temp.py", line 13, in Outer
foo = Child()
File "./temp.py", line 11, in __init__
Outer.Parent.__init__(self)
NameError: global name 'Outer' is not defined

Apparently, python doesn't like having an instance of a derived nested
class present in the outer class. Interestingly enough, if I change
the foo variable to an instance of the parent class:

foo = Parent()

everything is hunky-dory. Is there some syntax rule I'm breaking here?

It's simple - you try to refer to Outer whilst Outer itself is being
created. A much simpler version of your problem is this:


class Foo:
foo = Foo()

You have to live with that. Just do

Outer.foo = Outer.Parent()

after your class-statement to achieve the same result.

Diez
 
M

mrstephengross

class Foo:
foo = Foo()

You have to live with that. Just do
Outer.foo = Outer.Parent()
after your class-statement to achieve the same result.

Hmmm. Well, I see why that works. It's too bad, though. If I want to
keep all executed code safely within a "if __name__ == '__main__'"
block, it ends up a bit ugly. Then again, I guess this is just an
aspect of python I'll have to get used to. Is there a specific reason
it works this way, by chance?

--Steve
 
G

Gabriel Genellina

En Wed, 27 Feb 2008 16:52:57 -0200, mrstephengross
Hmmm. Well, I see why that works. It's too bad, though. If I want to
keep all executed code safely within a "if __name__ == '__main__'"
block, it ends up a bit ugly. Then again, I guess this is just an
aspect of python I'll have to get used to. Is there a specific reason
it works this way, by chance?

class statements (and def, and almost everything in Python) are
*executable* statements, not declarations.
When you import a module, it is executed. If it contains a class
statement, it is executed as follows: create an empty namespace (a dict),
execute the class body in it, create a new class object with __dict__ =
that namespace, and finally, bind the class name to the newly created
class object in the module namespace.
Until that last step, you can't refer to the class being created by name.

I don't get your issue with "if __name__==__main__", but I hope that you
now understand a bit better why a late initialization is required. (Of
course someone could come up with a metaclass to perform that late
initialization, but the important thing is to understand that you cannot
create an instance before the class itself exists)
 
D

Diez B. Roggisch

mrstephengross said:
Hmmm. Well, I see why that works. It's too bad, though. If I want to
keep all executed code safely within a "if __name__ == '__main__'"
block, it ends up a bit ugly. Then again, I guess this is just an
aspect of python I'll have to get used to. Is there a specific reason
it works this way, by chance?

Well, what would you think python should make of this?

class Foo:

f = Foo()

def __init__(self, argument):
pass


It can't possibly allow to instantiate an object of a class unless the
class creation is finished. Of course it could delay the execution of
anything but method definitions. But then the price would be high - loss
of generatlity, and for example this weren't possible as well:

class Bar:
if relative_moon_moisture() > 10:
def foo(self): pass
else:
def bar(self): pass


Diez
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,768
Messages
2,569,574
Members
45,050
Latest member
AngelS122

Latest Threads

Top