cassava
cassava

Reputation: 608

Do something automatically after class definition?

What I would like is the following:

lst = []

class Awesome:
  """This is my magical super class."""

  ...

class Inherits(Awesome):
  """Awesome does awesome stuff with Inherits."""
  name = "Stack"

class InheritsAgain(Awesome):
  name = "Overflow"

print(lst)
#: ['Stack', 'Overflow']

So basically, when the classes Inherits and InheritsAgain are defined, because they inherit from Awesome, Awesome has some metaclass magic (or whatever), that reads the attribute name from the inheriting class, and appends it to lst.

I've looked at the meta-classes in Python, but I'm not sure exactly how this would fit together.

Is this possible in Python? And if it is, how would you go about it?

Edit:

Let's add to the above example, so that this also works:

class AndAgain(Awesome):
  name = "/root/path/<name>/<id>"

  def go():
    pass

I want the whole class AndAgain to be defined, so that I can inspect and see that name exists with the value "/root/path/<name>/<id>", and the function go() also exists.

Upvotes: 1

Views: 81

Answers (2)

Ethan Furman
Ethan Furman

Reputation: 69031

lst = []

class AwesomeMeta(type):
    def __new__(metacls, cls, bases, classdict):
        if cls != 'Awesome':
            lst.append(cls)
        return super().__new__(metacls, cls, bases, classdict)

class Awesome(metaclass=AwesomeMeta):
  """This is my magical super class."""


class Stack(Awesome):
  """Awesome does awesome stuff with Inherits."""


class Overflow(Awesome):
    """More awesomely stuff!"""

print(lst)

And to show looking inside the class:

lst = []

class AwesomeMeta(type):
    def __new__(metacls, cls, bases, classdict):
        if 'name' in classdict:
            lst.append(classdict['name'])
        return super().__new__(metacls, cls, bases, classdict)

class Awesome(metaclass=AwesomeMeta):
    """This is my magical super class."""


class Inherits(Awesome):
    """Awesome does awesome stuff with Inherits."""

    name = 'Stack'


class InheritsAgain(Awesome):
    """More awesomely stuff!"""

    name = 'Overflow'

class AndAgain(Awesome):
    name = "/root/path/<name>/<id>"

    def go():
        pass

print(lst)

Upvotes: 2

oleg
oleg

Reputation: 4182

One can use metaclasses

class AwesomeMeta(type):
    lst = []
    def __new__(metacls, cls, bases, classdict):
        if 'name' in classdict:
            metacls.lst.append(classdict['name'])
        return super(AwesomeMeta, metacls).__new__(metacls, cls, bases, classdict)

class Awesome(object):
    """This is my magical super class."""
    __metaclass__ = AwesomeMeta


class Inherits(Awesome):
    """Awesome does awesome stuff with Inherits."""
    name = 'Stack'


class InheritsAgain(Awesome):
    """More awesomely stuff!"""
    name = 'Overflow'

print InheritsAgain.lst, Inherits.lst, Awesome.lst

or one can use __subclasses__ method

print [i.name for i in Awesome.__subclasses__()]

or One can use class decorator

lst = []
def cls_decorator(cls):
    lst.append(cls.name)
    return cls

@cls_decorator
class Awesome(object):
    """This is my magical super class."""
    name = 'Awesome'


@cls_decorator
class Inherits(Awesome):
    """Awesome does awesome stuff with Inherits."""
    name = 'Stack'


@cls_decorator
class InheritsAgain(Awesome):
    """More awesomely stuff!"""
    name = 'Overflow'

Solution should depend on what are You going to do

Upvotes: 1

Related Questions