12
votes

I am trying to reference an inner class from another inner class. I have tried both :

class Foo(object):

  class A(object):
    pass

  class B(object):
    other = A

and

class Foo(object):

  class A(object):
    pass

  class B(object):
    other = Foo.A

with respective results:

Traceback (most recent call last):
  File "python", line 1, in <module>
  File "python", line 6, in Foo
  File "python", line 7, in B
NameError: name 'A' is not defined

and

Traceback (most recent call last):
  File "python", line 1, in <module>
  File "python", line 6, in Foo
  File "python", line 7, in B
NameError: name 'Foo' is not defined

Is this possible?

1
Well clearly from your attempts the answer is no, but what are you trying to do here eventually? What problem are you trying to solve? - Burhan Khalid
Why do you have nested classes at all? They are very rarely useful in Python. - Daniel Roseman
Using classes is not always a good fit for the problem you are trying to solve. - Roland Smith
Part 1) I knew this would inevitably lead to "you're not using pythonic design." I'm aware of that, but that argument is largely subjective. My application has a few different models, e.g. User and Transaction, located in models/user.py and models/transaction.py, respectively. Both model classes have protorpc message classes, "Msg", e.g. User.Msg and Transaction.Msg. For the sake of import brevity and to maintain the namespace between the two message classes, I made them inner classes. - crunk1
Part 2) So, instead of "import user" and using "user.User" and "user.Msg", I could do "from user import User" and use "User" and "User.Msg". The example with "Transaction" is longer. The problem is that I also had a "Transaction.Status" that "Transaction.Msg" needed to reference. - crunk1

1 Answers

9
votes

This is not possible, since everything you define in a class becomes a valid member only in an instance of that class, unless you define a method with @staticmethod, but there is no such property for a class.

So, this won't work either:

class Foo(object):
    x = 10

    class A(object):
        pass

    class B(object):
        other = x

This will work, but it is not what you intended:

class Foo(object):
  x = 10

  class A(object):
    pass

  class B(object):
    def __init__(self):
        self.other = Foo.A

f = Foo()
print(f.B().other)

The output is:

<class '__main__.Foo.A'>

The reason this works is that the methods (in this case __init__) are evaluated when the object is created, while assignment before the __init__ are evaluated while the class is read and interpreted.

You can get about the same thing you want by simply define all the classes inside a module of their own. The importing the module, makes it an object whose fields are the classes you define in it.