- pzrq / subclass_utilities.py
- How to Find All the Subclasses of a Class?
- Solution If We Have the Class Object, Not Only the Class Name
- Recursive for All Subclasses
- If We Only Have the String Name of the Class
- Putting It All Together
- How to Find All the Subclasses of a Class Given its Name?
- What is a Class?
- What is Subclass?
- Find all the Subclasses of a Class Given its Name
- Example: General Method to Find Subclasses
- Example: Recursive Method to Find Subclasses
- Example: Find Subclasses using itertools Module
- Conclusion
pzrq / subclass_utilities.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
def get_all_subclasses ( python_class ): |
«»» |
Helper function to get all the subclasses of a class. |
:param python_class: Any Python class that implements __subclasses__() |
«»» |
python_class . __subclasses__ () |
subclasses = set () |
check_these = [ python_class ] |
while check_these : |
parent = check_these . pop () |
for child in parent . __subclasses__ (): |
if child not in subclasses : |
subclasses . add ( child ) |
check_these . append ( child ) |
return sorted ( subclasses , key = lambda x : x . __name__ ) |
def get_concrete_models ( base_model ): |
«»» |
Helper function to get all concrete models |
that are subclasses of base_model |
in sorted order by name. |
:param base_model: A Django models.Model instance. |
«»» |
found = get_all_subclasses ( base_model ) |
def filter_func ( model ): |
meta = getattr ( model , ‘_meta’ , » ) |
if getattr ( meta , ‘abstract’ , True ): |
# Skip meta classes |
return False |
if ‘_Deferred_’ in model . __name__ : |
# See deferred_class_factory() in django.db.models.query_utils |
# Catches when you do .only(‘attr’) on a queryset |
return False |
return True |
subclasses = list ( filter ( filter_func , found )) |
return sorted ( subclasses , key = lambda x : x . __name__ ) |
How to Find All the Subclasses of a Class?
Given a class by name (string). How to find all the subclasses of the given class?
Example: Here’s an example scenario with a subclass hierarchy.
class Parent: pass class Daughter(Parent): pass class Son(Parent): pass class Grandson(Son): pass
Desired outputs: Next, let’s quickly establish what you want to accomplish with two examples.
Given:Son
Result:Grandson
Given:Parent
Result:Daughter, Son
For the most basic cases, we don’t assume a recursive solution requirement, so we don’t consider Grandson also a subclass of Parent .
Solution If We Have the Class Object, Not Only the Class Name
Assume (for now), we have the class object. We’re looking at a slightly more complicated case without this assumption in the next section of this article.
In this case, we can simply get all subclasses of the class using the my_class.__subclasses__() magic method:
class Parent: pass class Daughter(Parent): pass class Son(Parent): pass class Grandson(Son): pass print(Parent.__subclasses__()) # [, ]
If you only need a list of all names of subclasses, and not the whole clutter around the output, you can use a list comprehension statement like so:
names = [cls.__name__ for cls in Parent.__subclasses__()] print(names) # ['Daughter', 'Son']
Recursive for All Subclasses
You can get all direct and indirect subclasses (if hierarchical inheritance is used) using a recursive approach:
- Create a function subclass_recursive() that takes one argument: the base class from which the subclasses should be found.
- Find all direct subclasses using the __subclasses__() magic method.
- Find all indirect subclasses by calling the function recursively.
- Return the concatenation of direct and indirect subclasses to the caller.
If you need a refresher on recursion, check out my in-depth tutorial here.
class Parent: pass class Daughter(Parent): pass class Son(Parent): pass class Grandson(Son): pass class GrandGrandSon(Son): pass def subclasses_recursive(cls): direct = cls.__subclasses__() indirect = [] for subclass in direct: indirect.extend(subclasses_recursive(subclass)) return direct + indirect print(subclasses_recursive(Parent))
The output is the list of all subclasses:
Again, if you need to have only the class names as strings, use list comprehension with the __name__ special attribute on the subclasses.
names = [cls.__name__ for cls in subclasses_recursive(Parent)] print(names) # ['Daughter', 'Son', 'Grandson', 'GrandGrandSon']
If We Only Have the String Name of the Class
You can use the globals() built-in function to find out the class object, given its name:
# Get class given name of class: base_name = 'Parent' base_class = globals()[base_name]
Feel free to watch my background video on the function next:
If this doesn’t work, you may want to check out the locals() function too.
# Get class given name of class: base_name = 'Parent' base_class = locals()[base_name]
Finally, another way to get the class given its full path is outlined here:
import importlib module_name, _, base_name = name.rpartition('.') module = importlib.import_module(module_name) base_class = getattr(module, base_name)
Putting It All Together
class Parent: pass class Daughter(Parent): pass class Son(Parent): pass class Grandson(Son): pass class GrandGrandSon(Son): pass # Get class given name of class: base_name = 'Parent' base_class = globals()[base_name] # Get list of direct subclasses: print(base_class.__subclasses__()) # [, ] # Get list of direct subclass names: names = [cls.__name__ for cls in base_class.__subclasses__()] print(names) # ['Daughter', 'Son'] # Get list of direct and indirect subclasses: def subclasses_recursive(cls): direct = cls.__subclasses__() indirect = [] for subclass in direct: indirect.extend(subclasses_recursive(subclass)) return direct + indirect # Get list of direct and indirect subclasse names: names = [cls.__name__ for cls in subclasses_recursive(base_class)] print(names) # ['Daughter', 'Son', 'Grandson', 'GrandGrandSon']
While working as a researcher in distributed systems, Dr. Christian Mayer found his love for teaching computer science students.
To help students reach higher levels of Python success, he founded the programming education website Finxter.com that has taught exponential skills to millions of coders worldwide. He’s the author of the best-selling programming books Python One-Liners (NoStarch 2020), The Art of Clean Code (NoStarch 2022), and The Book of Dash (NoStarch 2022). Chris also coauthored the Coffee Break Python series of self-published books. He’s a computer science enthusiast, freelancer, and owner of one of the top 10 largest Python blogs worldwide.
His passions are writing, reading, and coding. But his greatest passion is to serve aspiring coders through Finxter and help them to boost their skills. You can join his free email academy here.
Be on the Right Side of Change 🚀
- The world is changing exponentially. Disruptive technologies such as AI, crypto, and automation eliminate entire industries. 🤖
- Do you feel uncertain and afraid of being replaced by machines, leaving you without money, purpose, or value? Fear not! There a way to not merely survive but thrive in this new world!
- Finxter is here to help you stay ahead of the curve, so you can keep winning as paradigms shift.
Learning Resources 🧑💻
⭐ Boost your skills. Join our free email academy with daily emails teaching exponential with 1000+ tutorials on AI, data science, Python, freelancing, and Blockchain development!
Join the Finxter Academy and unlock access to premium courses 👑 to certify your skills in exponential technologies and programming.
New Finxter Tutorials:
Finxter Categories:
How to Find All the Subclasses of a Class Given its Name?
In this article, we will learn to how to find all subclasses of a class given its name in Python. We will look at the methodology, syntax, keywords, associated terms with some simple approaches, and some custom codes as well to better understand the topic of the class. Let’s first have a quick look over what is a class and a subclass in Python.
What is a Class?
Python is a popular scripting language. It also supports the object-oriented programming paradigm concepts. Object-Oriented Programming in Python involves object creation through Class , Inheritance , Polymorphism, and Encapsulation . A class is like a blueprint that bundles different types of items under one roof. Python can have multiple classes in one Python script. Each class contains its own attributes, instances, and methods to maintain the state of the class. Python classes have the ability to protect the data from outside threats. Classes are accessed from an entity called objects . It has methods called member functions to modify the state of the class. Assume your class to be a house that contains house details like room, kitchen, doors, etc. Likewise, Class has different attributes called data members that tell us about the class.
What is Subclass?
A class that is derived from another class is known as a subclass. This is a concept of inheritance in Python. The subclass derives or inherits the properties of another class.
Find all the Subclasses of a Class Given its Name
Since Python classes are first-class objects, «given its name» signifies that you do not need to use a string with the class’s name in place of the class. You can just use the class directly. New-style classes i.e. subclassed from an object, which is the default in Python 3 have a __subclasses__ method. This method returns the subclasses of the class.
Note: If the class definition of a subclass has not been executed yet, for example, if the subclass’s module has not been imported yet, then that subclass doesn’t exist yet, and __subclasses__ won’t find it.
Example: General Method to Find Subclasses
Look at the below code snippet, there are three self-explanatory print statements. This code snippet has one base class my_class and three subclasses A, B, C. The first print statement prints all the names of the subclasses using __subclassess__ method. The second print statement prints the subclasses itself rather than their names. Next, we use for loop and confirm from the output that A, B, C are the subclasses of the main class my_class.
class my_class(object): pass class A(my_class): pass class B(my_class): pass class C(my_class): pass #Here are the names of the subclasses: print([cls.__name__ for cls in my_class.__subclasses__()]) #Here are the subclasses themselves: print(my_class.__subclasses__()) #Confirmation that my_class is the base class: for cls in my_class.__subclasses__(): print(cls.__base__)
Example: Recursive Method to Find Subclasses
This is a simple, readable function that recursively finds all subclasses of a given class.
class my_class(object): pass class A(my_class): pass class B(my_class): pass class C(my_class): pass def get_all_subclasses(cls): all_subclasses = [] for subclass in cls.__subclasses__(): all_subclasses.append(subclass) all_subclasses.extend(get_all_subclasses(subclass)) return all_subclasses #pass base class as argument print(get_all_subclasses(my_class))
Example: Find Subclasses using itertools Module
This example is a much shorter version for getting a list of all subclasses. It imports chain from itertools module in Python.
class my_class(object): pass class A(my_class): pass class B(my_class): pass class C(my_class): pass from itertools import chain def get_all_subclasses(cls): return list( chain.from_iterable( [list(chain.from_iterable([[x], get_all_subclasses(x)])) for x in cls.__subclasses__()] ) ) print(get_all_subclasses(my_class))
Conclusion
In this article, we learned to find all the subclasses of the classes given their name using __subclassess__ method. We discussed three different examples of finding subclasses. We find subclasses using itertools chain module, we used the recursive method to get the list of all subclasses and a general method as well.