1

How do I implement super-like behavior in methods that are called before a class has been completely constructed. Can I implement a series of interdependent methods like this?

from six import with_metaclass

class Meta(type):
    """a metaclass"""

    def __init__(cls, name, bases, classdict):
        cls.setup_class()

    def setup_class(cls):
        pass


class A(with_metaclass(Meta, object)):
    """a class"""

    @classmethod
    def instantiate(cls, name):
        print("instantiating through '%s'" % name)

    @classmethod
    def setup_class(cls):
        cls.instantiate('A')


class B(A):

    @classmethod
    def setup_class(cls):
        super(B, cls).setup_class()
        cls.instantiate('B')

class C(B) pass

Obviously this can't work though, since B doesn't properly exist when setup_class is called.

Community
  • 1
  • 1
rmorshea
  • 832
  • 1
  • 7
  • 25

1 Answers1

1

I had this question for quite a while and couldn't really find a post that explained this aspect of metaclasses. In fact I had it for so long that I came up with this alternate, and ultimately unnecessary, solution. Technically it conforms exactly to the kind of syntax I wanted (which is cool) but in the end it's a hack. Since I spent so long making a pointless (but still cool) bit of code, I figured I'd at least try and make sure no one else got stuck in the same rut.

My confusion really stemmed from the fact that I hadn't fully extended my understanding of metaclasses, and the relationship they have with their classes, to its logical conclusion. So, as it turns out, the best way to create the kind of inheritance I wanted was actually to perform it inside a series of metaclasses - for the same reasons trying to inherit attributes through the instances of a class makes no sense, it makes no sense to be making the instances of a metaclass polymorphic:

from six import with_metaclass

class Meta(type):
    """a metaclass"""

    def __init__(cls, name, bases, classdict):
        print("Beginning '%s' setup" % name)
        cls.setup_class()
        print("Finished '%s' setup \n" % name)

    def setup_class(cls):
        cls.attribute = 0
        cls.instantiate('Meta')


class AMeta(Meta):

    def setup_class(cls):
        super(AMeta, cls).setup_class()
        cls.instantiate('A')

    def instantiate(cls, name):
        print("instantiating through '%s'" % name)

class A(with_metaclass(AMeta, object)): pass


class BMeta(AMeta):

    def setup_class(cls):
        super(BMeta, cls).setup_class()
        cls.instantiate('B')

class B(with_metaclass(BMeta, object)): pass


class C(B): pass

If anyone cares to more thoroughly examine this, I'm sure someone out there would appreciate it.

rmorshea
  • 832
  • 1
  • 7
  • 25