Albert
Albert

Reputation: 68110

Python: How to access outer class namespaces

Consider this code:

class A:
        B = 42  # or whatever
        class C:
                a = B  # wont find `B` here

That will not work because in class C, it wont find B.

You also cannot use A.B because also A is not known at this point because it is still being constructed and thus it is not in the global namespace. Inside a member function, that would work because at the point when you execute that code, the global name A is probably registered. However, I'm explicitly asking for the direct access, not inside a member function.

So, is there any other way in such nested class constructs to access the outer namespaces?

I guess the answer might be no, or at least not in a clean way. I added a print(locals()) inside of class C and with Python 2, I get {'__module__': '__main__'}, with Python 3, I get {'__qualname__': 'A.C', '__module__': '__main__'}. So neither the locals nor the globals will give me the access to the parent local namespace.

About a non-clean way: sys._getframe(1).f_locals["B"] will work. That are the locals of class A while it is being constructed, and B is in there.

So, if there is no clean way to do that, what are other solutions? I could declare all classes directly in the global namespace but I don't like that (for my specific use case). I could move them into a submodule and import them in A. But that makes the code more complicated to read. Any other solutions?


So, I guess it's always the same, unless I don't show a real-world example, people will not believe how such a use-case can happen. So, here it is (via):

class structs:
    # .... many more

    class _anonymous_label(ctypes.Structure):
        _fields_ = [
            ('lb_type', ctypes.c_int),
            ('lb_str', ctypes.POINTER(ctypes.c_byte))]

    class _anonymous_labellist(ctypes.Structure):
        _fields_ = [
            ('ll_nlabels', ctypes.c_int),
            ('ll_label', ctypes.POINTER(_anonymous_label))]  # error

    # .... many more

Upvotes: 4

Views: 782

Answers (4)

holdenweb
holdenweb

Reputation: 37003

I'd perform the class variable assignments for the inner classes in the outer class after the inner class declarations are complete. It's very little more complicated, completely obvious and it works:

class A:
    class B:
        a = 1
    class C:
        pass
    C.a = B.a

print(A.B.a, A.C.a)

Upvotes: 1

MisterMiyagi
MisterMiyagi

Reputation: 50076

You can always work with temporary objects which you don't expose. Depending on how your non-trivial example looks, this may not be appropriate, however.

# foo module
ABC_ATTRIBUTE = 42
class A:
  B = ABC_ATTRIBUTE
  class C:
    a = ABC_ATTRIBUTE
del ABC_ATTRIBUTE  # no longer accessible as foo.ABC_ATTRIBUTE

Upvotes: 0

Humbalan
Humbalan

Reputation: 717

What do you think about

var = 1
class A:
    class B:
        a = var
    class C:
        a = var

Upvotes: 0

Alex Hall
Alex Hall

Reputation: 36013

class Constants:
    a = 1

class A:
    class B(Constants):
        pass

    class C(Constants):
        pass

print(A.B.a, A.C.a)

Upvotes: 1

Related Questions