Search code examples
pythonstatic

python refer to parent class from static class


Is it possible to access the parent class name within a static class? For example, how to I print the parent class name in the bar method below?

class Static:
    def bar(self):
        parent_name = ???
        print(parent_name)

class A:
    object = Static()

    def foo(self):
        A.object.bar()

class B:
     object = Static()

    def foo(self):
        B.object.bar()

A().foo()
B().foo()

Solution

  • You're looking for the __set_name__ method.

    It is called on every static attribute of a class when the class is finished constructing. One of the parameters is the "owner" class (A or B), so all you need is to store that reference. Note that this requires a separate Static instance for each parent class, but you're doing that already.

    class Static:
        def bar(self):
            print(self.parent_name)
    
        def __set_name__(self, owner, name):
            self.parent_name = owner.__name__
    
    class A:
        object = Static()
    
        def foo(self):
            A.object.bar()
    
    class B:
        object = Static()
    
        def foo(self):
            B.object.bar()
    
    A().foo()
    B().foo()
    

    I personally avoid these magic methods when possible, so you might also consider taking @JonSG's advice and put the owner class in the Static constructor instead. This way the relationship is much clearer, at the cost of adding them after-the-fact.

    class Static:
        def __init__(self, owner):
            self.parent_name = owner.__name__
    
        def bar(self):
            print(self.parent_name)
    
    class A:
        def foo(self):
            A.object.bar()
    A.object = Static(A)
    
    class B:
        def foo(self):
            B.object.bar()
    B.object = Static(B)
    
    A().foo()
    B().foo()
    

    Alternatively, one might leverage a metaclass to do some of the work. This has the potential to also simplify the implementations of A() and B()

    class Static:
        def __init__(self, parent_name) -> None:
            self.parent_name = parent_name
    
        def bar(self):
            print(self.parent_name)
    
    class AB_Meta(type):
        def __init__(cls, name, bases, dct):
            cls.object = Static(name)
    
    class A(metaclass=AB_Meta):
        def foo(self):
            A.object.bar()
    
    class B(metaclass=AB_Meta):
        def foo(self):
            B.object.bar()
    
    A().foo()
    B().foo()
    

    Should give you:

    A
    B