Skip to main content
HomeAbout PythonLearn Python

Introduction to Python Metaclasses

In this tutorial, learn what metaclasses are, how to implement them in Python, and how to create custom ones.
Dec 2018  · 6 min read

A metaclass in Python is a class of a class that defines how a class behaves. A class is itself an instance of a metaclass. A class in Python defines how the instance of the class will behave. In order to understand metaclasses well, one needs to have prior experience working with Python classes. Before we dive deeper into metaclasses, let's get a few concepts out of the way.

Everything in Python is an Object

class TestClass():
    pass

my_test_class = TestClass()
print(my_test_class)
<__main__.TestClass object at 0x7f6fcc6bf908>

Python Classes can be Created Dynamically

type in Python enables us to find the type of an object. We can proceed to check the type of object we created above.

type(TestClass)
type
type(type)
type

Wait, What just happened? We'd expect the type of the object we created above to be class, but it's not. Hold on to that thought. We will cover it further in a few. We also notice that the type of type itself is type. It is an instance of type. Another magical thing that type does is enable us to create classes dynamically. Let's show how we'd do that below. The DataCamp class shown below would be created as shown below using type:

class DataCamp():
    pass
DataCampClass = type('DataCamp', (), {})
print(DataCampClass)
print(DataCamp())
<class '__main__.DataCamp'>
<__main__.DataCamp object at 0x7f6fcc66e358>

In the above example DataCamp is the class name while DataCampClass is the variable that holds the class reference. When using type we can pass attributes of the class using a dictionary as shown below:

PythonClass = type('PythonClass', (), {'start_date': 'August 2018', 'instructor': 'John Doe'} )
print(PythonClass.start_date, PythonClass.instructor)
print(PythonClass)
August 2018 John Doe
<class '__main__.PythonClass'>

In case we wanted our PythonClass to inherit from the DataCamp class we pass it to our second argument when defining the class using type

PythonClass = type('PythonClass', (DataCamp,), {'start_date': 'August 2018', 'instructor': 'John Doe'} )
print(PythonClass)
<class '__main__.PythonClass'>

Now that those two concepts are out of the way, we realize that Python creates the classes using a metaclass. We have seen that everything in Python is an object, these objects are created by metaclasses. Whenever we call class to create a class, there is a metaclass that does the magic of creating the class behind the scenes. We've already seen type do this in practice above. It is similar to str that creates strings and int that creates integers. In Python, the ___class__attribute enables us to check the type of the current instance. Let's create a string below and check its type.

article = 'metaclasses'
article.__class__
str

We can also check the type using type(article).

type(article)
str

When we check the type of str, we also find out that it's type.

type(str)
type

When we check the type for float, int, list, tuple, and dict, we will have a similar output. This is because all of these objects are of type type.

print(type(list),type(float), type(dict), type(tuple))
<class 'type'> <class 'type'> <class 'type'> <class 'type'>

We've already seen type creates classes. Hence when we check the __class__ of __class__ it should return type.

article.__class__.__class__
type

Master your data skills with DataCamp

More than 10 million people learn Python, R, SQL, and other tech skills using our hands-on courses crafted by industry experts.

Start Learning
learner-on-couch@2x.jpg

Creating Custom Metaclasses

In Python, we can customize the class creation process by passing the metaclass keyword in the class definition. This can also be done by inheriting a class that has already passed in this keyword.

class MyMeta(type):
    pass

class MyClass(metaclass=MyMeta):
    pass

class MySubclass(MyClass):
    pass

We can see below that the type of MyMeta class is type and that the type of MyClass and MySubClass is MyMeta.

print(type(MyMeta))
print(type(MyClass))
print(type(MySubclass))
<class 'type'>
<class '__main__.MyMeta'>
<class '__main__.MyMeta'>

When defining a class and no metaclass is defined the default type metaclass will be used. If a metaclass is given and it is not an instance of type(), then it is used directly as the metaclass.

__new__ and __init__

Metaclasses can also be defined in one of the two ways shown below. We'll explain the difference between them below.

class MetaOne(type):
    def __new__(cls, name, bases, dict):
        pass

class MetaTwo(type):
    def __init__(self, name, bases, dict):
        pass

__new__ is used when one wants to define dict or bases tuples before the class is created. The return value of __new__is usually an instance of cls. __new__ allows subclasses of immutable types to customize instance creation. It can be overridden in custom metaclasses to customize class creation. __init__ is usually called after the object has been created so as to initialize it.

Metaclass __call__ method

According to the official docs, we can also override other class methods by defining a custom __call__() method in the metaclass that allows custom behavior when the class is called.

Metaclass __prepare__ method

According to Python's data model docs

Once the appropriate metaclass has been identified, then the class namespace is prepared. If the metaclass has a __prepare__ attribute, it is called as namespace = metaclass.__prepare__(name, bases, **kwds) (where the additional keyword arguments, if any, come from the class definition). If the metaclass has no __prepare__attribute, then the class namespace is initialized as an empty ordered mapping. - docs.python.org

Singleton Design using a Metaclass

This is a design pattern that restricts the instantiation of a class to only one object. This could prove useful for example when designing a class to connect to the database. One might want to have just one instance of the connection class.

class SingletonMeta(type):
    _instances = {}
    def __call__(cls, *args, **kwargs):
        if cls not in cls._instances:
            cls._instances[cls] = super(SingletonMeta,cls).__call__(*args, **kwargs)
        return cls._instances[cls]

class SingletonClass(metaclass=SingletonMeta):
    pass

Conclusion

In this article, we have learned about what metaclasses are and how we can implement them in our Python programming. Metaclasses can be applied in logging, registration of classes at creation time and profiling among others. They seem to be quite abstract concepts, and you might be wondering if you need to use them at all. Long-term Pythonista, Tim Peters answers that question best.

"Metaclasses are deeper magic than 99% of users should ever worry about. If you wonder whether you need them, you don’t (the people who actually need them know with certainty that they need them, and don’t need an explanation about why).” - realpython

If you would like to learn more about Python, start DataCamp's Python Programming skill track and check out our Python Classes Tutorial.

References

Link one

Link two

Python Courses

Certification available

Introduction to Python

BeginnerSkill Level
4 hr
5.2M
Master the basics of data analysis with Python in just four hours. This online course will introduce the Python interface and explore popular packages.
See DetailsRight Arrow
Start Course
See MoreRight Arrow
Related

10 Essential Python Skills All Data Scientists Should Master

All data scientists need expertise in Python, but which skills are the most important for them to master? Find out the ten most vital Python skills in the latest rundown.

Thaylise Nakamoto

9 min

The 7 Best Python Certifications For All Levels

Find out whether a Python certification is right for you, what the best options are, and the alternatives on offer in this comprehensive guide.
Matt Crabtree's photo

Matt Crabtree

18 min

A Complete Guide to Socket Programming in Python

Learn the fundamentals of socket programming in Python
Serhii Orlivskyi's photo

Serhii Orlivskyi

41 min

Textacy: An Introduction to Text Data Cleaning and Normalization in Python

Discover how Textacy, a Python library, simplifies text data preprocessing for machine learning. Learn about its unique features like character normalization and data masking, and see how it compares to other libraries like NLTK and spaCy.

Mustafa El-Dalil

5 min

Coding Best Practices and Guidelines for Better Code

Learn coding best practices to improve your programming skills. Explore coding guidelines for collaboration, code structure, efficiency, and more.
Amberle McKee's photo

Amberle McKee

26 min

Pandas Profiling (ydata-profiling) in Python: A Guide for Beginners

Learn how to use the ydata-profiling library in Python to generate detailed reports for datasets with many features.
Satyam Tripathi's photo

Satyam Tripathi

9 min

See MoreSee More