35

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?

6
  • 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? Commented Feb 12, 2017 at 8:12
  • 1
    Why do you have nested classes at all? They are very rarely useful in Python. Commented Feb 12, 2017 at 9:01
  • Using classes is not always a good fit for the problem you are trying to solve. Commented Feb 12, 2017 at 9:25
  • 8
    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. Commented Feb 13, 2017 at 9:43
  • 1
    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. Commented Feb 13, 2017 at 9:47

4 Answers 4

21

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.

Sign up to request clarification or add additional context in comments.

3 Comments

Thanks for saving me from the "why would you do that in Python?" argument and helping me understand.
Yes, unfortunately, your solution will not work on my "class B." Class B has metaclass logic that processes the B class variables. And yes, I could reorganize the classes (they are in the same module anyway). I was trying to leverage the intrinsic namespacing on inner classes though.
You should probably clarify the statement: "since everything you define in a class becomes a valid member only in an instance of that class". Foo.x, Foo.A, Foo.B are attached to the class object, not the instance. You can ask for an id() of each of these class qualified members and see that they exist and they are the same for the instance qualified member access.
0

I don't think it's good object oriented practice, but you can set inner class attributes at the outer class scope. For instance.

class Class2: class Labels: c2l1 = 'label 1' c2l2 = 'label 2' class Params: pass # p1 = None # p2 = None # p3 = None Params.p1 = Labels.c2l2 Params.p2 = 1234 print(Class2.Params.p1) print(Class2.Params.p2) # print(Class2.Params.p3) 

label 2 1234 

These are all class attributes, but instance attributes should work similarly.

Comments

0

Another solution here is to turn Foo into a module and dedent the code.

Or One can do this by defining the B class by using the type function. This uses the Foo local scope.

class Foo(object): class A(object): pass B = type('B', (object,), {'other': A}) print(Foo.A) print(Foo.B) print(Foo.B.other) 

Prints out:

<class '__main__.Foo.A'> <class '__main__.B'> <class '__main__.Foo.A'> 

Comments

0

I have a similar problem, but since my initial issue was simply organizing multiple classes into a "namespace," this is what I've come up with:

class A: pass class B: other = A class Foo: A = A B = B 

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.