âčïž Skipped - page is already crawled
| Filter | Status | Condition | Details |
|---|---|---|---|
| HTTP status | PASS | download_http_code = 200 | HTTP 200 |
| Age cutoff | PASS | download_stamp > now() - 6 MONTH | 0.1 months ago |
| History drop | PASS | isNull(history_drop_reason) | No drop reason |
| Spam/ban | PASS | fh_dont_index != 1 AND ml_spam_score = 0 | ml_spam_score=0 |
| Canonical | PASS | meta_canonical IS NULL OR = '' OR = src_unparsed | Not set |
| Property | Value |
|---|---|
| URL | https://realpython.com/python-metaclasses/ |
| Last Crawled | 2026-04-16 00:16:05 (2 days ago) |
| First Indexed | 2018-05-01 14:57:04 (7 years ago) |
| HTTP Status Code | 200 |
| Meta Title | Python Metaclasses â Real Python |
| Meta Description | How Python's metaclasses work as an OOP concept, what they are good forâand why you might want to avoid them in your own programs. |
| Meta Canonical | null |
| Boilerpipe Text | The term
metaprogramming
refers to the potential for a program to have knowledge of or manipulate itself. Python supports a form of metaprogramming for classes called
metaclasses
.
Metaclasses are an esoteric
OOP concept
, lurking behind virtually all Python code. You are using them whether you are aware of it or not. For the most part, you donât need to be aware of it. Most Python programmers rarely, if ever, have to think about metaclasses.
When the need arises, however, Python provides a capability that not all object-oriented languages support: you can get under the hood and define custom metaclasses. The use of custom metaclasses is somewhat controversial, as suggested by the following quote from Tim Peters, the Python guru who authored the
Zen of Python
:
â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).â
â
Tim Peters
There are Pythonistas (as Python aficionados are known) who believe that you should never use custom metaclasses. That might be going a bit far, but it is probably true that custom metaclasses mostly arenât necessary. If it isnât pretty obvious that a problem calls for them, then it will probably be cleaner and more readable if solved in a simpler way.
Still, understanding Python metaclasses is worthwhile, because it leads to a better understanding of the internals of
Python classes
in general. You never know: you may one day find yourself in one of those situations where you just know that a custom metaclass is what you want.
Old-Style vs. New-Style Classes
In the Python realm, a class
can be one of two varieties
. No official terminology has been decided on, so they are informally referred to as old-style and new-style classes.
Old-Style Classes
With old-style classes, class and type are not quite the same thing. An instance of an old-style class is always implemented from a single built-in type called
instance
. If
obj
is an instance of an old-style class,
obj.__class__
designates the class, but
type(obj)
is always
instance
. The following example is taken from Python 2.7:
New-Style Classes
New-style classes unify the concepts of class and type. If
obj
is an instance of a new-style class,
type(obj)
is the same as
obj.__class__
:
Type and Class
In Python 3, all classes are new-style classes. Thus, in Python 3 it is reasonable to refer to an objectâs type and its class interchangeably.
Remember that,
in Python, everything is an object.
Classes are objects as well. As a result, a class must have a type. What is the type of a class?
Consider the following:
The type of
x
is class
Foo
, as you would expect. But the type of
Foo
, the class itself, is
type
. In general, the type of any new-style class is
type
.
The type of the built-in classes you are familiar with is also
type
:
For that matter, the type of
type
is
type
as well (yes, really):
type
is a metaclass, of which classes are instances. Just as an ordinary object is an instance of a class, any new-style class in Python, and thus any class in Python 3, is an instance of the
type
metaclass.
In the above case:
x
is an instance of class
Foo
.
Foo
is an instance of the
type
metaclass.
type
is also an instance of the
type
metaclass, so it is an instance of itself.
Defining a Class Dynamically
The built-in
type()
function, when passed one argument, returns the type of an object. For new-style classes, that is generally the same as the
objectâs
__class__
attribute
:
You can also call
type()
with three argumentsâ
type(<name>, <bases>, <dct>)
:
<name>
specifies the class name. This becomes the
__name__
attribute of the class.
<bases>
specifies a tuple of the base classes from which the class inherits. This becomes the
__bases__
attribute of the class.
<dct>
specifies a
namespace dictionary
containing definitions for the class body. This becomes the
__dict__
attribute of the class.
Calling
type()
in this manner creates a new instance of the
type
metaclass. In other words, it dynamically creates a new class.
In each of the following examples, the top snippet defines a class dynamically with
type()
, while the snippet below it defines the class the usual way, with the
class
statement. In each case, the two snippets are functionally equivalent.
Example 1
In this first example, the
<bases>
and
<dct>
arguments passed to
type()
are both empty. No
inheritance
from any parent class is specified, and nothing is initially placed in the namespace dictionary. This is the simplest class definition possible:
Example 2
Here,
<bases>
is a tuple with a single element
Foo
, specifying the parent class that
Bar
inherits from. An attribute,
attr
, is initially placed into the namespace dictionary:
Example 3
This time,
<bases>
is again empty. Two objects are placed into the namespace dictionary via the
<dct>
argument. The first is an attribute named
attr
and the second a function named
attr_val
, which becomes a method of the defined class:
Example 4
Only very simple functions can be defined with
lambda
in Python
. In the following example, a slightly more complex function is defined externally then assigned to
attr_val
in the namespace dictionary via the name
f
:
Consider again this well-worn example:
The expression
Foo()
creates a new instance of class
Foo
. When the interpreter encounters
Foo()
, the following occurs:
The
__call__()
method of
Foo
âs parent class is called. Since
Foo
is a standard new-style class, its parent class is the
type
metaclass, so
type
âs
__call__()
method is invoked.
That
__call__()
method in turn invokes the following:
__new__()
__init__()
If
Foo
does not define
__new__()
and
__init__()
, default methods are inherited from
Foo
âs ancestry. But if
Foo
does define these methods, they override those from the ancestry, which allows for customized behavior when instantiating
Foo
.
In the following, a custom method called
new()
is defined and assigned as the
__new__()
method for
Foo
:
This modifies the instantiation behavior of class
Foo
: each time an instance of
Foo
is created, by default it is initialized with an attribute called
attr
, which has a value of
100
. (Code like this would more usually appear in the
__init__()
method and not typically in
__new__()
. This example is contrived for demonstration purposes.)
Now, as has already been reiterated, classes are objects too. Suppose you wanted to similarly customize instantiation behavior when creating a class like
Foo
. If you were to follow the pattern above, youâd again define a custom method and assign it as the
__new__()
method for the class of which
Foo
is an instance.
Foo
is an instance of the
type
metaclass, so the code looks something like this:
Except, as you can see, you canât reassign the
__new__()
method of the
type
metaclass. Python doesnât allow it.
This is probably just as well.
type
is the metaclass from which all new-style classes are derived. You really shouldnât be mucking around with it anyway. But then what recourse is there, if you want to customize instantiation of a class?
One possible solution is a custom metaclass. Essentially, instead of mucking around with the
type
metaclass, you can define your own metaclass, which derives from
type
, and then you can muck around with that instead.
The first step is to define a metaclass that derives from
type
, as follows:
The definition header
class Meta(type):
specifies that
Meta
derives from
type
. Since
type
is a metaclass, that makes
Meta
a metaclass as well.
Note that a custom
__new__()
method has been defined for
Meta
. It wasnât possible to do that to the
type
metaclass directly. The
__new__()
method does the following:
Delegates via
super()
to the
__new__()
method of the parent metaclass (
type
) to actually create a new class
Assigns the custom attribute
attr
to the class, with a value of
100
Returns the newly created class
Now the other half of the voodoo: Define a new class
Foo
and specify that its metaclass is the custom metaclass
Meta
, rather than the standard metaclass
type
. This is done using the
metaclass
keyword in the class definition as follows:
Voila!
Foo
has picked up the
attr
attribute automatically from the
Meta
metaclass. Of course, any other classes you define similarly will do likewise:
In the same way that a class functions as a template for the creation of objects, a metaclass functions as a template for the creation of classes. Metaclasses are sometimes referred to as
class factories
.
Compare the following two examples:
Object Factory:
Class Factory:
Is This Really Necessary?
As simple as the above class factory example is, it is the essence of how metaclasses work. They allow customization of class instantiation.
Still, this is a lot of fuss just to bestow the custom attribute
attr
on each newly created class. Do you really need a metaclass just for that?
In Python, there are at least a couple other ways in which effectively the same thing can be accomplished:
Simple Inheritance:
Class Decorator:
Conclusion
As Tim Peters suggests,
metaclasses
can easily veer into the realm of being a âsolution in search of a problem.â It isnât typically necessary to create custom metaclasses. If the problem at hand can be solved in a simpler way, it probably should be. Still, it is beneficial to understand metaclasses so that you understand
Python classes
in general and can recognize when a metaclass really is the appropriate tool to use. |
| Markdown | [](https://realpython.com/)
- [Start Here](https://realpython.com/start-here/)
- [Learn Python](https://realpython.com/python-metaclasses/)
[Python Tutorials â In-depth articles and video courses](https://realpython.com/search?kind=article&kind=course&order=newest)
[Learning Paths â Guided study plans for accelerated learning](https://realpython.com/learning-paths/)
[Quizzes & Exercises â Check your learning progress](https://realpython.com/quizzes/)
[Browse Topics â Focus on a specific area or skill level](https://realpython.com/tutorials/all/)
[Community Chat â Learn with other Pythonistas](https://realpython.com/community/)
[Office Hours â Live Q\&A calls with Python experts](https://realpython.com/office-hours/)
[Live Courses â Live, instructor-led Python courses](https://realpython.com/live/)
[Podcast â Hear whatâs new in the world of Python](https://realpython.com/podcasts/rpp/)
[Books â Round out your knowledge and learn offline](https://realpython.com/products/books/)
[Reference â Concise definitions for common Python terms](https://realpython.com/ref/)
[Code Mentor âBeta Personalized code assistance & learning tools](https://realpython.com/mentor/)
[Unlock All Content â](https://realpython.com/account/join/)
- [More](https://realpython.com/python-metaclasses/)
[Learner Stories](https://realpython.com/learner-stories/) [Python Newsletter](https://realpython.com/newsletter/) [Python Job Board](https://www.pythonjobshq.com/) [Meet the Team](https://realpython.com/team/) [Become a Contributor](https://realpython.com/jobs/)
- [Search](https://realpython.com/search "Search")
- [Join](https://realpython.com/account/join/)
- [SignâIn](https://realpython.com/account/login/?next=%2Fpython-metaclasses%2F)
[Browse Topics](https://realpython.com/tutorials/all/)
[Guided Learning Paths](https://realpython.com/learning-paths/)
[Basics](https://realpython.com/search?level=basics)
[Intermediate](https://realpython.com/search?level=intermediate)
[Advanced](https://realpython.com/search?level=advanced)
***
[ai](https://realpython.com/tutorials/ai/) [algorithms](https://realpython.com/tutorials/algorithms/) [api](https://realpython.com/tutorials/api/) [best-practices](https://realpython.com/tutorials/best-practices/) [career](https://realpython.com/tutorials/career/) [community](https://realpython.com/tutorials/community/) [databases](https://realpython.com/tutorials/databases/) [data-science](https://realpython.com/tutorials/data-science/) [data-structures](https://realpython.com/tutorials/data-structures/) [data-viz](https://realpython.com/tutorials/data-viz/) [devops](https://realpython.com/tutorials/devops/) [django](https://realpython.com/tutorials/django/) [docker](https://realpython.com/tutorials/docker/) [editors](https://realpython.com/tutorials/editors/) [flask](https://realpython.com/tutorials/flask/) [front-end](https://realpython.com/tutorials/front-end/) [gamedev](https://realpython.com/tutorials/gamedev/) [gui](https://realpython.com/tutorials/gui/) [machine-learning](https://realpython.com/tutorials/machine-learning/) [news](https://realpython.com/tutorials/news/) [numpy](https://realpython.com/tutorials/numpy/) [projects](https://realpython.com/tutorials/projects/) [python](https://realpython.com/tutorials/python/) [stdlib](https://realpython.com/tutorials/stdlib/) [testing](https://realpython.com/tutorials/testing/) [tools](https://realpython.com/tutorials/tools/) [web-dev](https://realpython.com/tutorials/web-dev/) [web-scraping](https://realpython.com/tutorials/web-scraping/)
[Table of Contents](https://realpython.com/python-metaclasses/#toc)
- [Old-Style vs. New-Style Classes](https://realpython.com/python-metaclasses/#old-style-vs-new-style-classes)
- [Old-Style Classes](https://realpython.com/python-metaclasses/#old-style-classes)
- [New-Style Classes](https://realpython.com/python-metaclasses/#new-style-classes)
- [Type and Class](https://realpython.com/python-metaclasses/#type-and-class)
- [Defining a Class Dynamically](https://realpython.com/python-metaclasses/#defining-a-class-dynamically)
- [Example 1](https://realpython.com/python-metaclasses/#example-1)
- [Example 2](https://realpython.com/python-metaclasses/#example-2)
- [Example 3](https://realpython.com/python-metaclasses/#example-3)
- [Example 4](https://realpython.com/python-metaclasses/#example-4)
- [Custom Metaclasses](https://realpython.com/python-metaclasses/#custom-metaclasses)
- [Is This Really Necessary?](https://realpython.com/python-metaclasses/#is-this-really-necessary)
- [Conclusion](https://realpython.com/python-metaclasses/#conclusion)
Mark as Completed
Share
Recommended Course
[ Metaclasses in Python 51m · 7 lessons](https://realpython.com/courses/python-metaclasses/)

# Python Metaclasses
by [John Sturtz](https://realpython.com/python-metaclasses/#author)
Reading time estimate
12m
[22 Comments](https://realpython.com/python-metaclasses/#reader-comments)
[advanced](https://realpython.com/tutorials/advanced/) [python](https://realpython.com/tutorials/python/)
Mark as Completed
Share
Table of Contents
- [Old-Style vs. New-Style Classes](https://realpython.com/python-metaclasses/#old-style-vs-new-style-classes)
- [Old-Style Classes](https://realpython.com/python-metaclasses/#old-style-classes)
- [New-Style Classes](https://realpython.com/python-metaclasses/#new-style-classes)
- [Type and Class](https://realpython.com/python-metaclasses/#type-and-class)
- [Defining a Class Dynamically](https://realpython.com/python-metaclasses/#defining-a-class-dynamically)
- [Example 1](https://realpython.com/python-metaclasses/#example-1)
- [Example 2](https://realpython.com/python-metaclasses/#example-2)
- [Example 3](https://realpython.com/python-metaclasses/#example-3)
- [Example 4](https://realpython.com/python-metaclasses/#example-4)
- [Custom Metaclasses](https://realpython.com/python-metaclasses/#custom-metaclasses)
- [Is This Really Necessary?](https://realpython.com/python-metaclasses/#is-this-really-necessary)
- [Conclusion](https://realpython.com/python-metaclasses/#conclusion)
[Remove ads](https://realpython.com/account/join/)
Recommended Course
[Metaclasses in Python](https://realpython.com/courses/python-metaclasses/) (51m)
The term **metaprogramming** refers to the potential for a program to have knowledge of or manipulate itself. Python supports a form of metaprogramming for classes called **metaclasses**.
Metaclasses are an esoteric [OOP concept](https://realpython.com/python3-object-oriented-programming/), lurking behind virtually all Python code. You are using them whether you are aware of it or not. For the most part, you donât need to be aware of it. Most Python programmers rarely, if ever, have to think about metaclasses.
When the need arises, however, Python provides a capability that not all object-oriented languages support: you can get under the hood and define custom metaclasses. The use of custom metaclasses is somewhat controversial, as suggested by the following quote from Tim Peters, the Python guru who authored the [Zen of Python](https://realpython.com/zen-of-python/):
> â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).â
>
> â *Tim Peters*
There are Pythonistas (as Python aficionados are known) who believe that you should never use custom metaclasses. That might be going a bit far, but it is probably true that custom metaclasses mostly arenât necessary. If it isnât pretty obvious that a problem calls for them, then it will probably be cleaner and more readable if solved in a simpler way.
Still, understanding Python metaclasses is worthwhile, because it leads to a better understanding of the internals of [Python classes](https://realpython.com/python-classes/) in general. You never know: you may one day find yourself in one of those situations where you just know that a custom metaclass is what you want.
**Get Notified:** Donât miss the follow up to this tutorialâ[Click here to join the Real Python Newsletter](https://realpython.com/bonus/newsletter-dont-miss-updates/) and youâll know when the next installment comes out.
## Old-Style vs. New-Style Classes
In the Python realm, a class [can be one of two varieties](https://wiki.python.org/moin/NewClassVsClassicClass). No official terminology has been decided on, so they are informally referred to as old-style and new-style classes.
[Remove ads](https://realpython.com/account/join/)
### Old-Style Classes
With old-style classes, class and type are not quite the same thing. An instance of an old-style class is always implemented from a single built-in type called `instance`. If `obj` is an instance of an old-style class, `obj.__class__` designates the class, but `type(obj)` is always `instance`. The following example is taken from Python 2.7:
Python
```
```
### New-Style Classes
New-style classes unify the concepts of class and type. If `obj` is an instance of a new-style class, `type(obj)` is the same as `obj.__class__`:
Python
```
```
Python
```
```
## Type and Class
In Python 3, all classes are new-style classes. Thus, in Python 3 it is reasonable to refer to an objectâs type and its class interchangeably.
**Note:** In Python 2, classes are old-style by default. Prior to Python 2.2, new-style classes werenât supported at all. From Python 2.2 onward, they can be created but must be explicitly declared as new-style.
Remember that, [in Python, everything is an object.](https://web.archive.org/web/20151210024637/https://mail.python.org/pipermail/python-list/2015-June/691689.html) Classes are objects as well. As a result, a class must have a type. What is the type of a class?
Consider the following:
Python
```
```
The type of `x` is class `Foo`, as you would expect. But the type of `Foo`, the class itself, is `type`. In general, the type of any new-style class is `type`.
The type of the built-in classes you are familiar with is also `type`:
Python
```
```
For that matter, the type of `type` is `type` as well (yes, really):
Python
```
```
`type` is a metaclass, of which classes are instances. Just as an ordinary object is an instance of a class, any new-style class in Python, and thus any class in Python 3, is an instance of the `type` metaclass.
In the above case:
- `x` is an instance of class `Foo`.
- `Foo` is an instance of the `type` metaclass.
- `type` is also an instance of the `type` metaclass, so it is an instance of itself.
[](https://files.realpython.com/media/class-chain.5cb031a299fe.png)
[Remove ads](https://realpython.com/account/join/)
## Defining a Class Dynamically
The built-in `type()` function, when passed one argument, returns the type of an object. For new-style classes, that is generally the same as the [objectâs `__class__` attribute](https://docs.python.org/3/library/stdtypes.html#instance.__class__):
Python
```
```
You can also call `type()` with three argumentsâ`type(<name>, <bases>, <dct>)`:
- `<name>` specifies the class name. This becomes the `__name__` attribute of the class.
- `<bases>` specifies a tuple of the base classes from which the class inherits. This becomes the `__bases__` attribute of the class.
- `<dct>` specifies a [namespace dictionary](https://realpython.com/python-namespaces-scope/#python-namespace-dictionaries) containing definitions for the class body. This becomes the `__dict__` attribute of the class.
Calling `type()` in this manner creates a new instance of the `type` metaclass. In other words, it dynamically creates a new class.
In each of the following examples, the top snippet defines a class dynamically with `type()`, while the snippet below it defines the class the usual way, with the `class` statement. In each case, the two snippets are functionally equivalent.
### Example 1
In this first example, the `<bases>` and `<dct>` arguments passed to `type()` are both empty. No [inheritance](https://realpython.com/inheritance-composition-python/) from any parent class is specified, and nothing is initially placed in the namespace dictionary. This is the simplest class definition possible:
Python
```
```
Python
```
```
### Example 2
Here, `<bases>` is a tuple with a single element `Foo`, specifying the parent class that `Bar` inherits from. An attribute, `attr`, is initially placed into the namespace dictionary:
Python
```
```
Python
```
```
### Example 3
This time, `<bases>` is again empty. Two objects are placed into the namespace dictionary via the `<dct>` argument. The first is an attribute named `attr` and the second a function named `attr_val`, which becomes a method of the defined class:
Python
```
```
Python
```
```
### Example 4
Only very simple functions can be defined with [`lambda` in Python](https://dbader.org/blog/python-lambda-functions). In the following example, a slightly more complex function is defined externally then assigned to `attr_val` in the namespace dictionary via the name `f`:
Python
```
```
Python
```
```
[Remove ads](https://realpython.com/account/join/)
## Custom Metaclasses
Consider again this well-worn example:
Python
```
```
The expression `Foo()` creates a new instance of class `Foo`. When the interpreter encounters `Foo()`, the following occurs:
- The `__call__()` method of `Foo`âs parent class is called. Since `Foo` is a standard new-style class, its parent class is the `type` metaclass, so `type`âs `__call__()` method is invoked.
- That `__call__()` method in turn invokes the following:
- `__new__()`
- `__init__()`
If `Foo` does not define `__new__()` and `__init__()`, default methods are inherited from `Foo`âs ancestry. But if `Foo` does define these methods, they override those from the ancestry, which allows for customized behavior when instantiating `Foo`.
In the following, a custom method called `new()` is defined and assigned as the `__new__()` method for `Foo`:
Python
```
```
This modifies the instantiation behavior of class `Foo`: each time an instance of `Foo` is created, by default it is initialized with an attribute called `attr`, which has a value of `100`. (Code like this would more usually appear in the `__init__()` method and not typically in `__new__()`. This example is contrived for demonstration purposes.)
Now, as has already been reiterated, classes are objects too. Suppose you wanted to similarly customize instantiation behavior when creating a class like `Foo`. If you were to follow the pattern above, youâd again define a custom method and assign it as the `__new__()` method for the class of which `Foo` is an instance. `Foo` is an instance of the `type` metaclass, so the code looks something like this:
Python
```
```
Except, as you can see, you canât reassign the `__new__()` method of the `type` metaclass. Python doesnât allow it.
This is probably just as well. `type` is the metaclass from which all new-style classes are derived. You really shouldnât be mucking around with it anyway. But then what recourse is there, if you want to customize instantiation of a class?
One possible solution is a custom metaclass. Essentially, instead of mucking around with the `type` metaclass, you can define your own metaclass, which derives from `type`, and then you can muck around with that instead.
The first step is to define a metaclass that derives from `type`, as follows:
Python
```
```
The definition header `class Meta(type):` specifies that `Meta` derives from `type`. Since `type` is a metaclass, that makes `Meta` a metaclass as well.
Note that a custom `__new__()` method has been defined for `Meta`. It wasnât possible to do that to the `type` metaclass directly. The `__new__()` method does the following:
- Delegates via `super()` to the `__new__()` method of the parent metaclass (`type`) to actually create a new class
- Assigns the custom attribute `attr` to the class, with a value of `100`
- Returns the newly created class
Now the other half of the voodoo: Define a new class `Foo` and specify that its metaclass is the custom metaclass `Meta`, rather than the standard metaclass `type`. This is done using the `metaclass` keyword in the class definition as follows:
Python
```
```
*Voila\!* `Foo` has picked up the `attr` attribute automatically from the `Meta` metaclass. Of course, any other classes you define similarly will do likewise:
Python
```
```
In the same way that a class functions as a template for the creation of objects, a metaclass functions as a template for the creation of classes. Metaclasses are sometimes referred to as [class factories](https://en.wikipedia.org/wiki/Factory_\(object-oriented_programming\)).
Compare the following two examples:
**Object Factory:**
Python
```
```
**Class Factory:**
Python
```
```
[Remove ads](https://realpython.com/account/join/)
## Is This Really Necessary?
As simple as the above class factory example is, it is the essence of how metaclasses work. They allow customization of class instantiation.
Still, this is a lot of fuss just to bestow the custom attribute `attr` on each newly created class. Do you really need a metaclass just for that?
In Python, there are at least a couple other ways in which effectively the same thing can be accomplished:
**Simple Inheritance:**
Python
```
```
**Class Decorator:**
Python
```
```
## Conclusion
As Tim Peters suggests, **metaclasses** can easily veer into the realm of being a âsolution in search of a problem.â It isnât typically necessary to create custom metaclasses. If the problem at hand can be solved in a simpler way, it probably should be. Still, it is beneficial to understand metaclasses so that you understand [Python classes](https://realpython.com/python3-object-oriented-programming/) in general and can recognize when a metaclass really is the appropriate tool to use.
Mark as Completed
Share
Recommended Course
[Metaclasses in Python](https://realpython.com/courses/python-metaclasses/) (51m)
đ Python Tricks đ
Get a short & sweet **Python Trick** delivered to your inbox every couple of days. No spam ever. Unsubscribe any time. Curated by the Real Python team.

About **John Sturtz**
[ ](https://realpython.com/team/jsturtz/)
John is an avid Pythonista and a member of the Real Python tutorial team.
[» More about John](https://realpython.com/team/jsturtz/)
***
*Each tutorial at Real Python is created by a team of developers so that it meets our high quality standards. The team members who worked on this tutorial are:*
[](https://realpython.com/team/asantos/)
[Aldren](https://realpython.com/team/asantos/)
[](https://realpython.com/team/dbader/)
[Dan](https://realpython.com/team/dbader/)
[](https://realpython.com/team/jjablonski/)
[Joanna](https://realpython.com/team/jjablonski/)
Master Real-World Python Skills With Unlimited Access to Real Python

**Join us and get access to thousands of tutorials, hands-on video courses, and a community of expert Pythonistas:**
[Level Up Your Python Skills »](https://realpython.com/account/join/?utm_source=rp_article_footer&utm_content=python-metaclasses)
Master Real-World Python Skills
With Unlimited Access to Real Python

**Join us and get access to thousands of tutorials, hands-on video courses, and a community of expert Pythonistas:**
[Level Up Your Python Skills »](https://realpython.com/account/join/?utm_source=rp_article_footer&utm_content=python-metaclasses)
What Do You Think?
**Rate this article:**
[LinkedIn](https://www.linkedin.com/sharing/share-offsite/?url=https%3A%2F%2Frealpython.com%2Fpython-metaclasses%2F)
[Twitter](https://twitter.com/intent/tweet/?text=Interesting%20Python%20article%20on%20%40realpython%3A%20Python%20Metaclasses&url=https%3A%2F%2Frealpython.com%2Fpython-metaclasses%2F)
[Bluesky](https://bsky.app/intent/compose?text=Interesting%20Python%20article%20on%20%40realpython.com%3A%20Python%20Metaclasses%20https%3A%2F%2Frealpython.com%2Fpython-metaclasses%2F)
[Facebook](https://facebook.com/sharer/sharer.php?u=https%3A%2F%2Frealpython.com%2Fpython-metaclasses%2F)
[Email](mailto:?subject=Python%20article%20for%20you&body=Python%20Metaclasses%20on%20Real%20Python%0A%0Ahttps%3A%2F%2Frealpython.com%2Fpython-metaclasses%2F%0A)
Whatâs your \#1 takeaway or favorite thing you learned? How are you going to put your newfound skills to use? Leave a comment below and let us know.
**Commenting Tips:** The most useful comments are those written with the goal of learning from or helping out other students. [Get tips for asking good questions](https://realpython.com/python-beginner-tips/#tip-9-ask-good-questions) and [get answers to common questions in our support portal](https://support.realpython.com/).
***
Looking for a real-time conversation? Visit the [Real Python Community Chat](https://realpython.com/community/) or join the next [âOffice Hoursâ Live Q\&A Session](https://realpython.com/office-hours/). Happy Pythoning\!
Keep Learning
Related Topics: [advanced](https://realpython.com/tutorials/advanced/) [python](https://realpython.com/tutorials/python/)
Related Learning Paths:
- [Python Metaprogramming](https://realpython.com/learning-paths/metaprogramming-in-python/?utm_source=realpython&utm_medium=web&utm_campaign=related-learning-path&utm_content=python-metaclasses)
Related Courses:
- [Metaclasses in Python](https://realpython.com/courses/python-metaclasses/?utm_source=realpython&utm_medium=web&utm_campaign=related-course&utm_content=python-metaclasses)
Related Tutorials:
- [Primer on Python Decorators](https://realpython.com/primer-on-python-decorators/?utm_source=realpython&utm_medium=web&utm_campaign=related-post&utm_content=python-metaclasses)
- [Implementing an Interface in Python](https://realpython.com/python-interface/?utm_source=realpython&utm_medium=web&utm_campaign=related-post&utm_content=python-metaclasses)
- [Python Descriptors: An Introduction](https://realpython.com/python-descriptors/?utm_source=realpython&utm_medium=web&utm_campaign=related-post&utm_content=python-metaclasses)
- [Python's asyncio: A Hands-On Walkthrough](https://realpython.com/async-io-python/?utm_source=realpython&utm_medium=web&utm_campaign=related-post&utm_content=python-metaclasses)
- [Iterators and Iterables in Python: Run Efficient Iterations](https://realpython.com/python-iterators-iterables/?utm_source=realpython&utm_medium=web&utm_campaign=related-post&utm_content=python-metaclasses)
## Keep reading Real Python by creating a free account or signing in:
[](https://realpython.com/account/signup/?intent=continue_reading&utm_source=rp&utm_medium=web&utm_campaign=rwn&utm_content=v1&next=%2Fpython-metaclasses%2F)
[Continue »](https://realpython.com/account/signup/?intent=continue_reading&utm_source=rp&utm_medium=web&utm_campaign=rwn&utm_content=v1&next=%2Fpython-metaclasses%2F)
Already have an account? [Sign-In](https://realpython.com/account/login/?next=/python-metaclasses/)
Almost there! Complete this form and click the button below to gain instant access:
Ă

Join the Real Python Community Newsletter (More Than 45,468 Python Developers Have Subscribed)
##### Learn Python
- [Start Here](https://realpython.com/start-here/)
- [Learning Resources](https://realpython.com/search)
- [Code Mentor](https://realpython.com/mentor/)
- [Python Reference](https://realpython.com/ref/)
- [Python Cheat Sheet](https://realpython.com/cheatsheets/python/)
- [Support Center](https://support.realpython.com/)
##### Courses & Paths
- [Learning Paths](https://realpython.com/learning-paths/)
- [Quizzes & Exercises](https://realpython.com/quizzes/)
- [Browse Topics](https://realpython.com/tutorials/all/)
- [Live Courses](https://realpython.com/live/)
- [Books](https://realpython.com/books/)
##### Community
- [Podcast](https://realpython.com/podcasts/rpp/)
- [Newsletter](https://realpython.com/newsletter/)
- [Community Chat](https://realpython.com/community/)
- [Office Hours](https://realpython.com/office-hours/)
- [Learner Stories](https://realpython.com/learner-stories/)
##### Membership
- [Plans & Pricing](https://realpython.com/account/join/)
- [Team Plans](https://realpython.com/account/join-team/)
- [For Business](https://realpython.com/account/join-team/inquiry/)
- [For Schools](https://realpython.com/account/join-team/education-inquiry/)
- [Reviews](https://realpython.com/learner-stories/)
##### Company
- [About Us](https://realpython.com/about/)
- [Team](https://realpython.com/team/)
- [Mission & Values](https://realpython.com/mission/)
- [Editorial Guidelines](https://realpython.com/editorial-guidelines/)
- [Sponsorships](https://realpython.com/sponsorships/)
- [Careers](https://realpython.workable.com/)
- [Press Kit](https://realpython.com/media-kit/)
- [Merch](https://realpython.com/merch)
[Privacy Policy](https://realpython.com/privacy-policy/) â
[Terms of Use](https://realpython.com/terms/) â
[Security](https://realpython.com/security/) â
[Contact](https://realpython.com/contact/)
Happy Pythoning\!
© 2012â2026 DevCademy Media Inc. DBA Real Python. All rights reserved.
REALPYTHONâą is a trademark of DevCademy Media Inc.
[](https://realpython.com/)

You've blocked notifications |
| Readable Markdown | The term **metaprogramming** refers to the potential for a program to have knowledge of or manipulate itself. Python supports a form of metaprogramming for classes called **metaclasses**.
Metaclasses are an esoteric [OOP concept](https://realpython.com/python3-object-oriented-programming/), lurking behind virtually all Python code. You are using them whether you are aware of it or not. For the most part, you donât need to be aware of it. Most Python programmers rarely, if ever, have to think about metaclasses.
When the need arises, however, Python provides a capability that not all object-oriented languages support: you can get under the hood and define custom metaclasses. The use of custom metaclasses is somewhat controversial, as suggested by the following quote from Tim Peters, the Python guru who authored the [Zen of Python](https://realpython.com/zen-of-python/):
> â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).â
>
> â *Tim Peters*
There are Pythonistas (as Python aficionados are known) who believe that you should never use custom metaclasses. That might be going a bit far, but it is probably true that custom metaclasses mostly arenât necessary. If it isnât pretty obvious that a problem calls for them, then it will probably be cleaner and more readable if solved in a simpler way.
Still, understanding Python metaclasses is worthwhile, because it leads to a better understanding of the internals of [Python classes](https://realpython.com/python-classes/) in general. You never know: you may one day find yourself in one of those situations where you just know that a custom metaclass is what you want.
## Old-Style vs. New-Style Classes
In the Python realm, a class [can be one of two varieties](https://wiki.python.org/moin/NewClassVsClassicClass). No official terminology has been decided on, so they are informally referred to as old-style and new-style classes.
### Old-Style Classes
With old-style classes, class and type are not quite the same thing. An instance of an old-style class is always implemented from a single built-in type called `instance`. If `obj` is an instance of an old-style class, `obj.__class__` designates the class, but `type(obj)` is always `instance`. The following example is taken from Python 2.7:
### New-Style Classes
New-style classes unify the concepts of class and type. If `obj` is an instance of a new-style class, `type(obj)` is the same as `obj.__class__`:
## Type and Class
In Python 3, all classes are new-style classes. Thus, in Python 3 it is reasonable to refer to an objectâs type and its class interchangeably.
Remember that, [in Python, everything is an object.](https://web.archive.org/web/20151210024637/https://mail.python.org/pipermail/python-list/2015-June/691689.html) Classes are objects as well. As a result, a class must have a type. What is the type of a class?
Consider the following:
The type of `x` is class `Foo`, as you would expect. But the type of `Foo`, the class itself, is `type`. In general, the type of any new-style class is `type`.
The type of the built-in classes you are familiar with is also `type`:
For that matter, the type of `type` is `type` as well (yes, really):
`type` is a metaclass, of which classes are instances. Just as an ordinary object is an instance of a class, any new-style class in Python, and thus any class in Python 3, is an instance of the `type` metaclass.
In the above case:
- `x` is an instance of class `Foo`.
- `Foo` is an instance of the `type` metaclass.
- `type` is also an instance of the `type` metaclass, so it is an instance of itself.
[](https://files.realpython.com/media/class-chain.5cb031a299fe.png)
## Defining a Class Dynamically
The built-in `type()` function, when passed one argument, returns the type of an object. For new-style classes, that is generally the same as the [objectâs `__class__` attribute](https://docs.python.org/3/library/stdtypes.html#instance.__class__):
You can also call `type()` with three argumentsâ`type(<name>, <bases>, <dct>)`:
- `<name>` specifies the class name. This becomes the `__name__` attribute of the class.
- `<bases>` specifies a tuple of the base classes from which the class inherits. This becomes the `__bases__` attribute of the class.
- `<dct>` specifies a [namespace dictionary](https://realpython.com/python-namespaces-scope/#python-namespace-dictionaries) containing definitions for the class body. This becomes the `__dict__` attribute of the class.
Calling `type()` in this manner creates a new instance of the `type` metaclass. In other words, it dynamically creates a new class.
In each of the following examples, the top snippet defines a class dynamically with `type()`, while the snippet below it defines the class the usual way, with the `class` statement. In each case, the two snippets are functionally equivalent.
### Example 1
In this first example, the `<bases>` and `<dct>` arguments passed to `type()` are both empty. No [inheritance](https://realpython.com/inheritance-composition-python/) from any parent class is specified, and nothing is initially placed in the namespace dictionary. This is the simplest class definition possible:
### Example 2
Here, `<bases>` is a tuple with a single element `Foo`, specifying the parent class that `Bar` inherits from. An attribute, `attr`, is initially placed into the namespace dictionary:
### Example 3
This time, `<bases>` is again empty. Two objects are placed into the namespace dictionary via the `<dct>` argument. The first is an attribute named `attr` and the second a function named `attr_val`, which becomes a method of the defined class:
### Example 4
Only very simple functions can be defined with [`lambda` in Python](https://dbader.org/blog/python-lambda-functions). In the following example, a slightly more complex function is defined externally then assigned to `attr_val` in the namespace dictionary via the name `f`:
Consider again this well-worn example:
The expression `Foo()` creates a new instance of class `Foo`. When the interpreter encounters `Foo()`, the following occurs:
- The `__call__()` method of `Foo`âs parent class is called. Since `Foo` is a standard new-style class, its parent class is the `type` metaclass, so `type`âs `__call__()` method is invoked.
- That `__call__()` method in turn invokes the following:
- `__new__()`
- `__init__()`
If `Foo` does not define `__new__()` and `__init__()`, default methods are inherited from `Foo`âs ancestry. But if `Foo` does define these methods, they override those from the ancestry, which allows for customized behavior when instantiating `Foo`.
In the following, a custom method called `new()` is defined and assigned as the `__new__()` method for `Foo`:
This modifies the instantiation behavior of class `Foo`: each time an instance of `Foo` is created, by default it is initialized with an attribute called `attr`, which has a value of `100`. (Code like this would more usually appear in the `__init__()` method and not typically in `__new__()`. This example is contrived for demonstration purposes.)
Now, as has already been reiterated, classes are objects too. Suppose you wanted to similarly customize instantiation behavior when creating a class like `Foo`. If you were to follow the pattern above, youâd again define a custom method and assign it as the `__new__()` method for the class of which `Foo` is an instance. `Foo` is an instance of the `type` metaclass, so the code looks something like this:
Except, as you can see, you canât reassign the `__new__()` method of the `type` metaclass. Python doesnât allow it.
This is probably just as well. `type` is the metaclass from which all new-style classes are derived. You really shouldnât be mucking around with it anyway. But then what recourse is there, if you want to customize instantiation of a class?
One possible solution is a custom metaclass. Essentially, instead of mucking around with the `type` metaclass, you can define your own metaclass, which derives from `type`, and then you can muck around with that instead.
The first step is to define a metaclass that derives from `type`, as follows:
The definition header `class Meta(type):` specifies that `Meta` derives from `type`. Since `type` is a metaclass, that makes `Meta` a metaclass as well.
Note that a custom `__new__()` method has been defined for `Meta`. It wasnât possible to do that to the `type` metaclass directly. The `__new__()` method does the following:
- Delegates via `super()` to the `__new__()` method of the parent metaclass (`type`) to actually create a new class
- Assigns the custom attribute `attr` to the class, with a value of `100`
- Returns the newly created class
Now the other half of the voodoo: Define a new class `Foo` and specify that its metaclass is the custom metaclass `Meta`, rather than the standard metaclass `type`. This is done using the `metaclass` keyword in the class definition as follows:
*Voila\!* `Foo` has picked up the `attr` attribute automatically from the `Meta` metaclass. Of course, any other classes you define similarly will do likewise:
In the same way that a class functions as a template for the creation of objects, a metaclass functions as a template for the creation of classes. Metaclasses are sometimes referred to as [class factories](https://en.wikipedia.org/wiki/Factory_\(object-oriented_programming\)).
Compare the following two examples:
**Object Factory:**
**Class Factory:**
## Is This Really Necessary?
As simple as the above class factory example is, it is the essence of how metaclasses work. They allow customization of class instantiation.
Still, this is a lot of fuss just to bestow the custom attribute `attr` on each newly created class. Do you really need a metaclass just for that?
In Python, there are at least a couple other ways in which effectively the same thing can be accomplished:
**Simple Inheritance:**
**Class Decorator:**
## Conclusion
As Tim Peters suggests, **metaclasses** can easily veer into the realm of being a âsolution in search of a problem.â It isnât typically necessary to create custom metaclasses. If the problem at hand can be solved in a simpler way, it probably should be. Still, it is beneficial to understand metaclasses so that you understand [Python classes](https://realpython.com/python3-object-oriented-programming/) in general and can recognize when a metaclass really is the appropriate tool to use. |
| Shard | 71 (laksa) |
| Root Hash | 13351397557425671 |
| Unparsed URL | com,realpython!/python-metaclasses/ s443 |