2

Given a class inheriting from an abstract class, I'd like to be able to get all of its subclasses, but from within the class itself.

I've managed to create a @classmethod doing just that:

>>> Eukaryota.get_subtypes()
[<class '__main__.Plantae'>, <class '__main__.Fungi'>]

but is there a way I could do that using @property or through class attribute?

>>> Eukaryota.subtypes
[<class '__main__.Plantae'>, <class '__main__.Fungi'>]

(It seems that properties are only for intances of a class, not the class itself.)

Here is the one with @classmethod (using taxonomy):

from abc import ABCMeta, abstractmethod


class Kingdom(object):
    __metaclass__ = ABCMeta

    @classmethod
    @abstractmethod
    def get_subtypes(cls):
        pass


class Prokaryota(Kingdom):
    @classmethod
    def get_subtypes(cls):
        return cls.__subclasses__()


class Eukaryota(Kingdom):
    @classmethod
    def get_subtypes(cls):
        return cls.__subclasses__()

class Bacteria(Prokaryota):
    pass


class Plantae(Eukaryota):
    pass


class Fungi(Eukaryota):
    pass
eyllanesc
  • 235,170
  • 19
  • 170
  • 241
user30987
  • 41
  • 1
  • 5
  • I think the duplicate linked answers your question; ping me (use @Reblochon) in a comment if it doesn't. – Reblochon Masque Sep 13 '18 at 06:24
  • @ReblochonMasque I did originally also flag this as duplicate, but OP really wants to know how to access classmethods from within an instance... which is just a matter of calling it directly, or indirectly (from within a `@property`) through `return type(self).get_subtypes()` – metatoaster Sep 13 '18 at 06:27
  • @ReblochonMasque metatoaster is right in that I want to know if there's a way to do the example in the second code box: `Eukaryota.subtypes` returning list of `Eukaryota`'s subclasses Unless you think it's a bad idea. – user30987 Sep 13 '18 at 06:30
  • I have no idea if it is a good or a bad idea, IDK your use case. However, I am struggling to understand how the dupe (unutbu's answer)does not answer your question. – Reblochon Masque Sep 13 '18 at 06:32
  • I reopened, but you probably ought to clarify exactly what the issue you are facing is. Possible duplicate with https://stackoverflow.com/questions/3862310/how-to-find-all-the-subclasses-of-a-class-given-its-name – Reblochon Masque Sep 13 '18 at 06:37
  • @ReblochonMasque This question is about how to make a class method available as a property-like attribute, not about how to access the subclasses of a class (the title is misleading but the description explains what the OP wants). – blhsing Sep 13 '18 at 06:39
  • @ReblochonMasque Edited my comment but essentially I'm wondering if I can get all subclasses from the base class' *class* attribute, not instance, or from a separate function taking the base class as argument. I wanted to use something like Enum but with hierarchy. If you know of a better method, I'd appreciate any input. (I'm still curious about my question though) – user30987 Sep 13 '18 at 06:41
  • ok, could it possibly be edited in order to make that completely clear (including the title) please, @blhsing – Reblochon Masque Sep 13 '18 at 06:41
  • 1
    This question seems disjointed and unmotivated. Why is it important that the class inherits from an abstract class? Why the emphasis on "from within the class itself", especially since you're accessing this thing from outside the class? Why did you write `get_subtypes` when `__subclasses__` already exists? What's wrong with `__subclasses__` - do you have something against the parentheses? – user2357112 Sep 13 '18 at 06:43
  • 1
    @user2357112 You're right.. I think I was just stuck. and I agree it's not at all necessary to get it as a class attribute (i can use `__subclasses__` or the answer Reblochon Masque linked) but I was just wondering if there's a way – user30987 Sep 13 '18 at 06:47

1 Answers1

1

You can use a descriptor class:

class get_subclasses:
    def __get__(self, obj, objtype):
        return objtype.__subclasses__()

class Eukaryota(Kingdom):
    subtypes = get_subclasses()

so that Eukaryota.subtypes would return:

[<class '__main__.Plantae'>, <class '__main__.Fungi'>]
Patrick Haugh
  • 59,226
  • 13
  • 88
  • 96
blhsing
  • 91,368
  • 6
  • 71
  • 106