đŸ•·ïž Crawler Inspector

URL Lookup

Direct Parameter Lookup

Raw Queries and Responses

1. Shard Calculation

Query:
Response:
Calculated Shard: 71 (from laksa138)

2. Crawled Status Check

Query:
Response:

3. Robots.txt Check

Query:
Response:

4. Spam/Ban Check

Query:
Response:

5. Seen Status Check

â„č Skipped - page is already crawled

📄
INDEXABLE
✅
CRAWLED
2 days ago
đŸ€–
ROBOTS ALLOWED

Page Info Filters

FilterStatusConditionDetails
HTTP statusPASSdownload_http_code = 200HTTP 200
Age cutoffPASSdownload_stamp > now() - 6 MONTH0.1 months ago
History dropPASSisNull(history_drop_reason)No drop reason
Spam/banPASSfh_dont_index != 1 AND ml_spam_score = 0ml_spam_score=0
CanonicalPASSmeta_canonical IS NULL OR = '' OR = src_unparsedNot set

Page Details

PropertyValue
URLhttps://realpython.com/python-metaclasses/
Last Crawled2026-04-16 00:16:05 (2 days ago)
First Indexed2018-05-01 14:57:04 (7 years ago)
HTTP Status Code200
Meta TitlePython Metaclasses – Real Python
Meta DescriptionHow 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 Canonicalnull
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
[![Real Python](https://realpython.com/static/real-python-logo.893c30edea53.svg)](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 [![Python Metaclasses and Metaprogramming](https://files.realpython.com/media/Python-Metaclasses_Watermarked.e11d11543ff2.jpg) Metaclasses in Python 51m · 7 lessons](https://realpython.com/courses/python-metaclasses/) ![Python Metaclasses and Metaprogramming](https://files.realpython.com/media/Python-Metaclasses_Watermarked.e11d11543ff2.jpg) # 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. [![Python class chain](https://files.realpython.com/media/class-chain.5cb031a299fe.png)](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. ![Python Tricks Dictionary Merge](https://realpython.com/static/pytrick-dict-merge.4201a0125a5e.png) About **John Sturtz** [![John Sturtz](https://realpython.com/cdn-cgi/image/width=1920,height=1920,fit=crop,gravity=auto,format=auto/https://files.realpython.com/media/real-python-logo-square.28474fda9228_1.146e987bf77c.png) ![John Sturtz](https://realpython.com/cdn-cgi/image/width=1920,height=1920,fit=crop,gravity=auto,format=auto/https://files.realpython.com/media/real-python-logo-square.28474fda9228_1.146e987bf77c.png)](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:* [![Aldren Santos](https://realpython.com/cdn-cgi/image/width=500,height=500,fit=crop,gravity=auto,format=auto/https://files.realpython.com/media/Aldren_Santos_Real_Python.6b0861d8b841.png)](https://realpython.com/team/asantos/) [Aldren](https://realpython.com/team/asantos/) [![Dan Bader](https://realpython.com/cdn-cgi/image/width=1000,height=1000,fit=crop,gravity=auto,format=auto/https://files.realpython.com/media/daniel-square.d58bf4388750.jpg)](https://realpython.com/team/dbader/) [Dan](https://realpython.com/team/dbader/) [![Joanna Jablonski](https://realpython.com/cdn-cgi/image/width=800,height=800,fit=crop,gravity=auto,format=auto/https://files.realpython.com/media/jjablonksi-avatar.e37c4f83308e.jpg)](https://realpython.com/team/jjablonski/) [Joanna](https://realpython.com/team/jjablonski/) Master Real-World Python Skills With Unlimited Access to Real Python ![Locked learning resources](https://realpython.com/static/videos/lesson-locked.f5105cfd26db.svg) **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 ![Locked learning resources](https://realpython.com/static/videos/lesson-locked.f5105cfd26db.svg) **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: [![Keep reading](https://realpython.com/static/videos/lesson-locked.f5105cfd26db.svg)](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: × ![Real Python Logo](https://files.realpython.com/media/real-python-logo-square.28474fda9228.png) 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. [![Real Python - Online Python Training (logo)](https://realpython.com/static/real-python-logo-primary.973743b6d39d.svg)](https://realpython.com/) ![](https://www.facebook.com/tr?id=2220911568135371&ev=PageView&noscript=1) 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. [![Python class chain](https://files.realpython.com/media/class-chain.5cb031a299fe.png)](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.
Shard71 (laksa)
Root Hash13351397557425671
Unparsed URLcom,realpython!/python-metaclasses/ s443