Python super() can't call parent's inherited method - python

I have a question in Python that seems very complex to me, that combines inheritance, recursion, and the super() function.
First of all, I am using Python 3, and I have a structure of deep inheritance.
In the very first parent class I declare a method, and I want that method to be called from each child class in the hierarchy, but with different inputs for each of them.
The use of that structure seems very pythonic to me and it really saves me from a lot of code repetition.
A simplified sample of my code is shown below:
class ClassA(object):
def __init__(self):
self.attr = 'a'
#classmethod
def _classname(cls):
return cls.__name__
def method1(self):
if self._classname() != 'ClassA': #don't call it for the very first parent class
super().method1()
print(self.attr)
class ClassB(ClassA):
def __init__(self):
self.attr = 'b'
class ClassC(ClassB):
def __init__(self):
self.attr = 'c'
inst1 = ClassC()
inst1.method1()
I expect that code to print
'a'
'b'
'c'
Instead it raises an attribute error:
super().method1()
AttributeError: 'super' object has no attribute 'method1'
I know that it is a complex problem, but I have tried to divide it. I tried to remove the recursion part, but I do not get any better.
Based on the various attempts I have done, I believe that I am very close to the cause of the problem, and it seems to me like a syntax problem or something that simple.
Thanks!!

I'm afraid you have built up the wrong mental model on how Python instances and classes relate. Classes only provide a series of attributes for instances to 'inherit', not separate namespaces for instance attributes to live in. When you look up an attribute on an instance and the attribute doesn't exist on the instance itself, a search is done of the classes that back the instance, with the 'nearest' class with that attribute winning over others. super() just lets you reach attributes with the same name but defined on a next class in that same layered search space.
In order for super() to work correctly, Python records what class the method1 function was defined on. Here that's ClassA, and super() will only find attributes on the parent classes of ClassA. In your example, ClassC and ClassB had already been searched and they didn't have a method1 attribute, so ClassA.method1 is being used, but there is no further method1 attribute in the rest of the layers that are searched (only object remains, and there is no object.method1).
You don't need to use super() when subclasses are not overriding a method, nor can you do what you want with super() anyway. Note that the ClassB and ClassC subclasses do not get a copy of the method at all, there is no ClassC.method1 direct attribute that needs to account for ClassB.method1 to exist, etc. Again, what happens when looking up attributes on an instance is that all class objects in the inheritance hierarchy of the instance are inspected for that attribute, in a specific order.
Take a look at your subclasses:
>>> inst1
<__main__.ClassC object at 0x109a9dfd0>
>>> type(inst1)
<class '__main__.ClassC'>
>>> type(inst1).__mro__
(<class '__main__.ClassC'>, <class '__main__.ClassB'>, <class '__main__.ClassA'>, <class 'object'>)
The __mro__ attribute gives you the method resolution order of your ClassC class object; it is this order that attributes are searched for, and that super() uses to further search for attributes. To find inst1.method, Python will step through each of the objects in type(inst1).__mro__ and will return the first hit, so ClassA.method1.
In your example, you used super() in the ClassA.method1() definition. Python has attached some information to that function object to help further searches of attributes:
>>> ClassA.method1.__closure__
(<cell at 0x109a3fee8: type object at 0x7fd7f5cd5058>,)
>>> ClassA.method1.__closure__[0].cell_contents
<class '__main__.ClassA'>
>>> ClassA.method1.__closure__[0].cell_contents is ClassA
True
When you call super() the closure I show above is used to start a search along the type(self).__mro__ sequence, starting at the next object past the one named in the closure. It doesn't matter that there are subclasses here, so even for your inst1 object everything is skipped an only object is inspected:
>>> type(inst1).__mro__.index(ClassA) # where is ClassA in the sequence?
2
>>> type(inst1).__mro__[2 + 1:] # `super().method1` will only consider these objects, *past* ClassA
(<class 'object'>,)
At no point are ClassB or ClassC involved here anymore. The MRO depends on the class hierarchy of the current instance, and you can make radical changes when you start using multiple inheritance. Adding in extra classes into a hierarchy can alter the MRO enough to insert something between ClassA and object:
>>> class Mixin(object):
... def method1(self):
... print("I am Mixin.method1!")
...
>>> class ClassD(ClassA, Mixin): pass
...
>>> ClassD.__mro__
(<class '__main__.ClassD'>, <class '__main__.ClassA'>, <class '__main__.Mixin'>, <class 'object'>)
>>> ClassD.__mro__[ClassD.__mro__.index(ClassA) + 1:]
(<class '__main__.Mixin'>, <class 'object'>)
ClassD inherits from ClassA and from Mixin. Mixin inherits from object too. Python follows some complicated rules to put all classes in the hierarchy into a logical linear order, and Mixin ends up between ClassA and object because it inherits from the latter, and not the former.
Because Mixin is injected into the MRO after ClassA, calling Class().method1() changes how super().method1() behaves, and suddenly calling that method will do something different:
>>> ClassD().method1()
I am Mixin.method1!
a
Remember, it helps to see classes as a layered search space for attributes on instances! instance.attribute is searched for along the classes if the attribute doesn't exist on the instance itself. super() just let you search for the same attribute along the remainder of that search space.
This lets you reuse method implementations when implementing a method with the same name in a subclass. That's the whole point of super()!
There are other problems with your code.
When looking up methods, they are bound to the object they were looked up on. instance.method binds the method to instance, so that when you call instance.method(), Python knows what to pass into the method as self. For classmethod objects, self is replaced with type(self), unless you did ClassObject.attribute, at which point ClassObject is used.
So your _classname method will always be producing ClassC for inst1, as the cls object that is passed in is that of the current instance. super() doesn't change what class classmethods are bound to when accessed on an instance! It'll always be type(self).
You also forgot to call super() in the ClassB and ClassC __init__ methods, so for inst1, only ClassC.__init__ is ever actually used. The ClassB.__init__ and ClassC.__init__ implementations are never called. You'd have to add a call to super().__init__() in both for that to happen, at which point there are three self.attr = ... assignments on the same instance, and only the one that executes last will remain. There is no separate self for each of the classes that make up the code for the instance, so there are no separate self.attr attributes with different values.
Again, that's because inst1.__init__() is called, __init__ is bound to inst for the self argument, and even if you used super().__init__() the self that is passed on remains inst1.
What you want to achieve is something entirely different from an attribute search across all of the classes. Printing all class names can be done with a loop over __mro__ instead:
class ClassA(object):
def method2(self):
this_class = __class__ # this uses the same closure as super()!
for cls in type(self).__mro__:
print(cls.__name__)
if cls is this_class:
break
class ClassB(ClassA): pass
class ClassC(ClassB): pass
This then produces:
>>> inst1 = ClassC()
>>> inst1.method2()
ClassC
ClassB
ClassA
If you have to print 'c', 'b', 'a' you can add extra attributes to each class:
class ClassA(object):
_class_attr = 'a'
def method2(self):
this_class = __class__ # this uses the same closure as super()!
for cls in type(self).__mro__:
if hasattr(cls, '_class_attr'):
print(cls._class_attr)
class ClassB(ClassA):
_class_attr = 'b'
class ClassC(ClassB):
_class_attr = 'c'
and you'll get
c
b
a
printed.

Thats because you're trying to access Method1() on Object_class
def method1(self):
# this will print the class name you're calling from, if you are confused.
print(self._classname())
print(self.attr)
You've written an if-else which satisfies when you're instantialize with Class C and access method1().
To print a,b,c, you will need override the method in every class.. and calling super from them.
However, this will still have a problem. Because the self attribute carries the instance of Class C, not Class B or A. So, they can't access the attribute that you're initializing in the init func.
Final code looks like this
class ClassA(object):
def __init__(self):
self.attr = 'a'
#classmethod
def _classname(cls):
return cls.__name__
def method1(self):
print(self._classname())
#don't call it for the very first parent class
#super().method1()
print(self.attr)
class ClassB(ClassA):
def __init__(self):
self.attr = 'b'
def method1(self):
print(self._classname())
print(self.attr)
super().method1()
class ClassC(ClassB):
def __init__(self):
self.attr = 'c'
def method1(self):
print(self._classname())
print(self.attr)
super().method1()
inst1 = ClassC()
inst1.method1()

Related

How do overridden method calls from base-class methods work?

According to the docs on inheritance:
Derived classes may override methods of their base classes. Because methods have no special privileges when calling other methods of the same object, a method of a base class that calls another method defined in the same base class may end up calling a method of a derived class that overrides it.
How does that happen? Can someone illustrate this concept with a simple example?
Here's the example you requested. This prints chocolate.
class Base:
def foo(self):
print("foo")
def bar(self):
self.foo()
class Derived(Base):
def foo(self):
print("chocolate")
d = Derived()
d.bar() # prints "chocolate"
The string chocolate is printed instead of foo because Derived overrides the foo() function. Even though bar() is defined in Base, it ends up calling the Derived implementation of foo() instead of the Base implementation.
How does it work?
When an attribute look-up is performed on an instance of the class, the class dictionary and the dictionaries of its base classes are searched in a certain order (see: Method Resolution Order) for the appropriate method. What is found first is going to get called.
Using the following Spam example:
class Spam:
def produce_spam(self):
print("spam")
def get_spam(self):
self.produce_spam()
class SuperSpam(Spam):
def produce_spam(self):
print("super spam")
Spam defines the functions produce_spam and get_spam. These live in its Spam.__dict__ (class namespace). The sub-class SuperSpam, by means of inheritance, has access to both these methods. SuperSpam.produce_spam doesn't replace Spam.produce_spam, it is simply found first when the look-up for the name 'produce_spam' is made on one of its instances.
Essentially, the result of inheritance is that the dictionaries of any base classes are also going to get searched if, after an attribute look-up on the sub-class is made, the attribute isn't found in the sub-class's dictionary.
When the function get_spam is first invoked with:
s = SuperSpam()
s.get_spam()
the sequence of events roughly goes like this:
Look into SuperSpams __dict__ for get_spam.
Since it isn't found in SuperSpams __dict__ look into the dictionaries of it's base classes (mro chain).
Spam is next in the mro chain, so get_spam is found in Spam's dictionary.
Now, when produce_spam is looked up in the body of get_spam with self.produce_spam, the sequence is much shorter:
Look into SuperSpam's (self) __dict__ for produce_spam.
Find it, get it and call it.
produce_spam is found in the __dict__ first so that gets fetched.
class Base():
def m1(self):
return self.m2()
def m2(self):
return 'base'
class Sub(Base):
def m2(self):
return 'sub'
b = Base()
s = Sub()
print(b.m1(), s.m1())
prints "base sub"
To illustrate how it works consider these two classes:
class Parent(object):
def eat(self):
print("I don't want to eat that {}.".format(self.takefrompocket()))
def takefrompocket(self):
return 'apple'
def __getattribute__(self, name):
print('Looking for:', name)
method_to_use = object.__getattribute__(self, name)
print('Found method:', method_to_use)
return method_to_use
class Child(Parent):
def takefrompocket(self):
return 'salad'
The __getattribute__ method is responsible in new-style-classes (like all classes in python3) for the attribute lookup. It is just implemented to print what each lookup does - normally you don't want to and shouldn't implement it yourself. The lookup follows pythons method resolution order (MRO) just if you are really interested.
>>> some_kid = Child()
>>> some_kid.eat()
Looking for: eat
Found method: <bound method Parent.eat of <__main__.Child object at 0x0000027BCA4EEA58>>
Looking for: takefrompocket
Found method: <bound method Child.takefrompocket of <__main__.Child object at 0x0000027BCA4EEA58>>
I don't want to eat that salad.
So when you want to use eat then it uses Parent.eat in this example. But self.takefrompocket is used from Child.
>>> some_parent = Parent()
>>> some_parent.eat()
Looking for: eat
Found method: <bound method Parent.eat of <__main__.Parent object at 0x0000027BCA4EE358>>
Looking for: takefrompocket
Found method: <bound method Parent.takefrompocket of <__main__.Parent object at 0x0000027BCA4EE358>>
I don't want to eat that apple.
Here both methods are taken from Parent. Inherited classes don't (generally) interfere with their ancestors!
If your child class doesn't implement the method, raise an exception!
class Base(object):
def something (self):
raise ('Not implemented')

What class is super(classname, instance) actually calling?

I've seen a bunch of the python method resolution order questions on Stack Overflow, many of which are excellently answered. I have one that does not quite fit.
When requesting super(MyClassName, self).method_name, I get a type that is not returned by the (single) parent class. Putting debug into the parent class shows that it isn't hit.
I would add some code snippets, but the codebase is massive. I have been into every class listed from MyClassName.__mro__ (which tells us what the method resolution order is) and NONE of them return the type I'm getting. So the question is...
What tool or attribute in Python can I use to find out what code is actually being called so that if this happens again I can easily find out what is actually being called? I ended up finding the solution, but I'd rather know how to tackle it in a less labour intensive manner.
You can use e.g. inspect.getmodule to, per its documentation:
Try to guess which module an object was defined in.
A simple example, with a.py:
class Parent(object):
def method(self):
return True
and b.py:
import inspect
from a import Parent
class Child(Parent):
def method(self):
parent_method = super(Child, self).method # get the parent method
print "inherited method defined in {}".format(
inspect.getmodule(parent_method), # and find out where it came from
)
return parent_method()
if __name__ == '__main__':
Child().method()
Running b.py gives the result:
Parent defined in <module 'a' from 'C:/Python27\a.py'>
I think you might be getting confused between what a bound method is, and what the method resolution order is.
The returned method still counts as a bound method of the class of the actual object, even if function the method derives from is found on the parent class. This is because the method has been bound to an instance of the child class as opposed to the parent class.
eg.
class A:
def f(self):
return "A"
class B(A):
def g(self):
return super().f
class C(B):
def f(self):
return "C"
c = C()
method = c.g()
print(method) # prints <bound method C.f of <__main__.C object at 0x02D4FA10>>
print(method()) # prints A
In this instance, c.g() returns the function A.f bound to an instance of C.
To find the actual function that the bound method will call just examine the __func__ attribute:
assert method.__func__ is A.f

How do I call the parent method of a class inside completely non-related class?

I want to use the superclass to call the parent method of a class while using a different class.
Class AI():
...
for i in self.initial_computer_group:
if i.rect.x == current_coords[0] and i.rect. y== current_coords[1]:
i.move(coords_to_move[0], coords_to_move[1])
i.move() calls a method from an inherited class, when I want the original method from the parent class.
self.initial_computer_group contains a list of objects which are completely unrelated to the AI class.
I know I need to somehow get the class name of the current object i references to, but then I don't know what to use as the second argument in super() as i can't use self, since it's unrelated to AI.
So how do I use super() when I'm in a completely different class to what super is meant to call?
Note: I want to call the parent method as it speeds everything up. I only designed the inherited method to ensure the human isn't breaking the rules in this chess game.
EDIT: I found a solution by changing the name of the inherited method to something else, but I was wondering whether there's still a special way to invoke super() to solve the problem
It sounds like you want to call a specific class's method, no matter what the inheritance graph looks like (and in particular, even if that method happens to be overridden twice). In that case, you don't want super. Instead, call the class's method directly. For example, assuming the version you want is in the Foo class:
Foo.move(i, coords_to_move[0], coords_to_move[1])
As it's hard to read code in comments, here's a simple example:
class BaseClass():
def func(self):
print("Here in BaseClass.")
class InheritedClass(BaseClass):
def func(self):
print("Here in InheritedClass.")
def func(instance):
super(InheritedClass, instance).func()
In use:
>>> func(InheritedClass())
Here in BaseClass.
But this clearly makes your code less flexible (as the instance argument must be an InheritedClass instance), and should generally be avoided.
Given some inheritance hierarchy:
class Super: # descends from object
def func():
return 'Super calling'
class Base(Super):
def func():
return 'Base calling'
class Sub(Base):
def func():
return 'Sub calling'
You can get the resolution hierarchy with the __mro__ attribute:
>>> s=Sub()
>>> s.__class__.__mro__
(<class '__main__.Sub'>, <class '__main__.Base'>, <class '__main__.Super'>, <class 'object'>)
Then you can pick among those by index:
>>> s.__class__.__mro__[-2]
<class '__main__.Super'>
>>> s.__class__.__mro__[-2].func()
Super calling
You can get a specific name by matching against the __name__ attribute:
def by_name(inst, tgt):
for i, c in enumerate(inst.__class__.__mro__):
if c.__name__==tgt:
return i
return -1
Then if you want to call the parent class of an unrelated class, just use one of these methods on an instance of the descendant class with the method of interest.
Of course the simplest answer is if you know the class and method you want, just call it directly:
>>> Super.func()
Super calling
>>> Base.func()
Base calling
If you need to go several levels up (or an unknown number of levels up) to find the method, Python will do that for you:
class Super:
def func():
return 'Super calling'
class Base(Super):
pass
class Sub(Base):
pass
>>> Sub.func()
Super calling

Why are django model classes not of type "type"? [duplicate]

What are metaclasses? What are they used for?
Classes as objects
Before understanding metaclasses, it helps to understand Python classes more deeply. Python has a very peculiar idea of what classes are, which it borrows from the Smalltalk language.
In most languages, classes are just pieces of code that describe how to produce an object. That is somewhat true in Python too:
>>> class ObjectCreator(object):
... pass
>>> my_object = ObjectCreator()
>>> print(my_object)
<__main__.ObjectCreator object at 0x8974f2c>
But classes are more than that in Python. Classes are objects too.
Yes, objects.
When a Python script runs, every line of code is executed from top to bottom. When the Python interpreter encounters the class keyword, Python creates an object out of the "description" of the class that follows. Thus, the following instruction
>>> class ObjectCreator(object):
... pass
...creates an object with the name ObjectCreator!
This object (the class) is itself capable of creating objects (called instances).
But still, it's an object. Therefore, like all objects:
you can assign it to a variable1
JustAnotherVariable = ObjectCreator
you can attach attributes to it
ObjectCreator.class_attribute = 'foo'
you can pass it as a function parameter
print(ObjectCreator)
1 Note that merely assigning it to another variable doesn't change the class's __name__, i.e.,
>>> print(JustAnotherVariable)
<class '__main__.ObjectCreator'>
>>> print(JustAnotherVariable())
<__main__.ObjectCreator object at 0x8997b4c>
Creating classes dynamically
Since classes are objects, you can create them on the fly, like any object.
First, you can create a class in a function using class:
>>> def choose_class(name):
... if name == 'foo':
... class Foo(object):
... pass
... return Foo # return the class, not an instance
... else:
... class Bar(object):
... pass
... return Bar
...
>>> MyClass = choose_class('foo')
>>> print(MyClass) # the function returns a class, not an instance
<class '__main__.Foo'>
>>> print(MyClass()) # you can create an object from this class
<__main__.Foo object at 0x89c6d4c>
But it's not so dynamic, since you still have to write the whole class yourself.
Since classes are objects, they must be generated by something.
When you use the class keyword, Python creates this object automatically. But as
with most things in Python, it gives you a way to do it manually.
Remember the function type? The good old function that lets you know what
type an object is:
>>> print(type(1))
<type 'int'>
>>> print(type("1"))
<type 'str'>
>>> print(type(ObjectCreator))
<type 'type'>
>>> print(type(ObjectCreator()))
<class '__main__.ObjectCreator'>
Well, type has also a completely different ability: it can create classes on the fly. type can take the description of a class as parameters,
and return a class.
(I know, it's silly that the same function can have two completely different uses according to the parameters you pass to it. It's an issue due to backward
compatibility in Python)
type works this way:
type(name, bases, attrs)
Where:
name: name of the class
bases: tuple of the parent class (for inheritance, can be empty)
attrs: dictionary containing attributes names and values
e.g.:
>>> class MyShinyClass(object):
... pass
can be created manually this way:
>>> MyShinyClass = type('MyShinyClass', (), {}) # returns a class object
>>> print(MyShinyClass)
<class '__main__.MyShinyClass'>
>>> print(MyShinyClass()) # create an instance with the class
<__main__.MyShinyClass object at 0x8997cec>
You'll notice that we use MyShinyClass as the name of the class
and as the variable to hold the class reference. They can be different,
but there is no reason to complicate things.
type accepts a dictionary to define the attributes of the class. So:
>>> class Foo(object):
... bar = True
Can be translated to:
>>> Foo = type('Foo', (), {'bar':True})
And used as a normal class:
>>> print(Foo)
<class '__main__.Foo'>
>>> print(Foo.bar)
True
>>> f = Foo()
>>> print(f)
<__main__.Foo object at 0x8a9b84c>
>>> print(f.bar)
True
And of course, you can inherit from it, so:
>>> class FooChild(Foo):
... pass
would be:
>>> FooChild = type('FooChild', (Foo,), {})
>>> print(FooChild)
<class '__main__.FooChild'>
>>> print(FooChild.bar) # bar is inherited from Foo
True
Eventually, you'll want to add methods to your class. Just define a function
with the proper signature and assign it as an attribute.
>>> def echo_bar(self):
... print(self.bar)
...
>>> FooChild = type('FooChild', (Foo,), {'echo_bar': echo_bar})
>>> hasattr(Foo, 'echo_bar')
False
>>> hasattr(FooChild, 'echo_bar')
True
>>> my_foo = FooChild()
>>> my_foo.echo_bar()
True
And you can add even more methods after you dynamically create the class, just like adding methods to a normally created class object.
>>> def echo_bar_more(self):
... print('yet another method')
...
>>> FooChild.echo_bar_more = echo_bar_more
>>> hasattr(FooChild, 'echo_bar_more')
True
You see where we are going: in Python, classes are objects, and you can create a class on the fly, dynamically.
This is what Python does when you use the keyword class, and it does so by using a metaclass.
What are metaclasses (finally)
Metaclasses are the 'stuff' that creates classes.
You define classes in order to create objects, right?
But we learned that Python classes are objects.
Well, metaclasses are what create these objects. They are the classes' classes,
you can picture them this way:
MyClass = MetaClass()
my_object = MyClass()
You've seen that type lets you do something like this:
MyClass = type('MyClass', (), {})
It's because the function type is in fact a metaclass. type is the
metaclass Python uses to create all classes behind the scenes.
Now you wonder "why the heck is it written in lowercase, and not Type?"
Well, I guess it's a matter of consistency with str, the class that creates
strings objects, and int the class that creates integer objects. type is
just the class that creates class objects.
You see that by checking the __class__ attribute.
Everything, and I mean everything, is an object in Python. That includes integers,
strings, functions and classes. All of them are objects. And all of them have
been created from a class:
>>> age = 35
>>> age.__class__
<type 'int'>
>>> name = 'bob'
>>> name.__class__
<type 'str'>
>>> def foo(): pass
>>> foo.__class__
<type 'function'>
>>> class Bar(object): pass
>>> b = Bar()
>>> b.__class__
<class '__main__.Bar'>
Now, what is the __class__ of any __class__ ?
>>> age.__class__.__class__
<type 'type'>
>>> name.__class__.__class__
<type 'type'>
>>> foo.__class__.__class__
<type 'type'>
>>> b.__class__.__class__
<type 'type'>
So, a metaclass is just the stuff that creates class objects.
You can call it a 'class factory' if you wish.
type is the built-in metaclass Python uses, but of course, you can create your
own metaclass.
The __metaclass__ attribute
In Python 2, you can add a __metaclass__ attribute when you write a class (see next section for the Python 3 syntax):
class Foo(object):
__metaclass__ = something...
[...]
If you do so, Python will use the metaclass to create the class Foo.
Careful, it's tricky.
You write class Foo(object) first, but the class object Foo is not created
in memory yet.
Python will look for __metaclass__ in the class definition. If it finds it,
it will use it to create the object class Foo. If it doesn't, it will use
type to create the class.
Read that several times.
When you do:
class Foo(Bar):
pass
Python does the following:
Is there a __metaclass__ attribute in Foo?
If yes, create in-memory a class object (I said a class object, stay with me here), with the name Foo by using what is in __metaclass__.
If Python can't find __metaclass__, it will look for a __metaclass__ at the MODULE level, and try to do the same (but only for classes that don't inherit anything, basically old-style classes).
Then if it can't find any __metaclass__ at all, it will use the Bar's (the first parent) own metaclass (which might be the default type) to create the class object.
Be careful here that the __metaclass__ attribute will not be inherited, the metaclass of the parent (Bar.__class__) will be. If Bar used a __metaclass__ attribute that created Bar with type() (and not type.__new__()), the subclasses will not inherit that behavior.
Now the big question is, what can you put in __metaclass__?
The answer is something that can create a class.
And what can create a class? type, or anything that subclasses or uses it.
Metaclasses in Python 3
The syntax to set the metaclass has been changed in Python 3:
class Foo(object, metaclass=something):
...
i.e. the __metaclass__ attribute is no longer used, in favor of a keyword argument in the list of base classes.
The behavior of metaclasses however stays largely the same.
One thing added to metaclasses in Python 3 is that you can also pass attributes as keyword-arguments into a metaclass, like so:
class Foo(object, metaclass=something, kwarg1=value1, kwarg2=value2):
...
Read the section below for how Python handles this.
Custom metaclasses
The main purpose of a metaclass is to change the class automatically,
when it's created.
You usually do this for APIs, where you want to create classes matching the
current context.
Imagine a stupid example, where you decide that all classes in your module
should have their attributes written in uppercase. There are several ways to
do this, but one way is to set __metaclass__ at the module level.
This way, all classes of this module will be created using this metaclass,
and we just have to tell the metaclass to turn all attributes to uppercase.
Luckily, __metaclass__ can actually be any callable, it doesn't need to be a
formal class (I know, something with 'class' in its name doesn't need to be
a class, go figure... but it's helpful).
So we will start with a simple example, by using a function.
# the metaclass will automatically get passed the same argument
# that you usually pass to `type`
def upper_attr(future_class_name, future_class_parents, future_class_attrs):
"""
Return a class object, with the list of its attribute turned
into uppercase.
"""
# pick up any attribute that doesn't start with '__' and uppercase it
uppercase_attrs = {
attr if attr.startswith("__") else attr.upper(): v
for attr, v in future_class_attrs.items()
}
# let `type` do the class creation
return type(future_class_name, future_class_parents, uppercase_attrs)
__metaclass__ = upper_attr # this will affect all classes in the module
class Foo(): # global __metaclass__ won't work with "object" though
# but we can define __metaclass__ here instead to affect only this class
# and this will work with "object" children
bar = 'bip'
Let's check:
>>> hasattr(Foo, 'bar')
False
>>> hasattr(Foo, 'BAR')
True
>>> Foo.BAR
'bip'
Now, let's do exactly the same, but using a real class for a metaclass:
# remember that `type` is actually a class like `str` and `int`
# so you can inherit from it
class UpperAttrMetaclass(type):
# __new__ is the method called before __init__
# it's the method that creates the object and returns it
# while __init__ just initializes the object passed as parameter
# you rarely use __new__, except when you want to control how the object
# is created.
# here the created object is the class, and we want to customize it
# so we override __new__
# you can do some stuff in __init__ too if you wish
# some advanced use involves overriding __call__ as well, but we won't
# see this
def __new__(upperattr_metaclass, future_class_name,
future_class_parents, future_class_attrs):
uppercase_attrs = {
attr if attr.startswith("__") else attr.upper(): v
for attr, v in future_class_attrs.items()
}
return type(future_class_name, future_class_parents, uppercase_attrs)
Let's rewrite the above, but with shorter and more realistic variable names now that we know what they mean:
class UpperAttrMetaclass(type):
def __new__(cls, clsname, bases, attrs):
uppercase_attrs = {
attr if attr.startswith("__") else attr.upper(): v
for attr, v in attrs.items()
}
return type(clsname, bases, uppercase_attrs)
You may have noticed the extra argument cls. There is
nothing special about it: __new__ always receives the class it's defined in, as the first parameter. Just like you have self for ordinary methods which receive the instance as the first parameter, or the defining class for class methods.
But this is not proper OOP. We are calling type directly and we aren't overriding or calling the parent's __new__. Let's do that instead:
class UpperAttrMetaclass(type):
def __new__(cls, clsname, bases, attrs):
uppercase_attrs = {
attr if attr.startswith("__") else attr.upper(): v
for attr, v in attrs.items()
}
return type.__new__(cls, clsname, bases, uppercase_attrs)
We can make it even cleaner by using super, which will ease inheritance (because yes, you can have metaclasses, inheriting from metaclasses, inheriting from type):
class UpperAttrMetaclass(type):
def __new__(cls, clsname, bases, attrs):
uppercase_attrs = {
attr if attr.startswith("__") else attr.upper(): v
for attr, v in attrs.items()
}
# Python 2 requires passing arguments to super:
return super(UpperAttrMetaclass, cls).__new__(
cls, clsname, bases, uppercase_attrs)
# Python 3 can use no-arg super() which infers them:
return super().__new__(cls, clsname, bases, uppercase_attrs)
Oh, and in Python 3 if you do this call with keyword arguments, like this:
class Foo(object, metaclass=MyMetaclass, kwarg1=value1):
...
It translates to this in the metaclass to use it:
class MyMetaclass(type):
def __new__(cls, clsname, bases, dct, kwargs1=default):
...
That's it. There is really nothing more about metaclasses.
The reason behind the complexity of the code using metaclasses is not because
of metaclasses, it's because you usually use metaclasses to do twisted stuff
relying on introspection, manipulating inheritance, vars such as __dict__, etc.
Indeed, metaclasses are especially useful to do black magic, and therefore
complicated stuff. But by themselves, they are simple:
intercept a class creation
modify the class
return the modified class
Why would you use metaclasses classes instead of functions?
Since __metaclass__ can accept any callable, why would you use a class
since it's obviously more complicated?
There are several reasons to do so:
The intention is clear. When you read UpperAttrMetaclass(type), you know
what's going to follow
You can use OOP. Metaclass can inherit from metaclass, override parent methods. Metaclasses can even use metaclasses.
Subclasses of a class will be instances of its metaclass if you specified a metaclass-class, but not with a metaclass-function.
You can structure your code better. You never use metaclasses for something as trivial as the above example. It's usually for something complicated. Having the ability to make several methods and group them in one class is very useful to make the code easier to read.
You can hook on __new__, __init__ and __call__. Which will allow you to do different stuff, Even if usually you can do it all in __new__,
some people are just more comfortable using __init__.
These are called metaclasses, damn it! It must mean something!
Why would you use metaclasses?
Now the big question. Why would you use some obscure error-prone feature?
Well, usually you don't:
Metaclasses are deeper magic that
99% of users should never worry about it.
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).
Python Guru Tim Peters
The main use case for a metaclass is creating an API. A typical example of this is the Django ORM. It allows you to define something like this:
class Person(models.Model):
name = models.CharField(max_length=30)
age = models.IntegerField()
But if you do this:
person = Person(name='bob', age='35')
print(person.age)
It won't return an IntegerField object. It will return an int, and can even take it directly from the database.
This is possible because models.Model defines __metaclass__ and
it uses some magic that will turn the Person you just defined with simple statements
into a complex hook to a database field.
Django makes something complex look simple by exposing a simple API
and using metaclasses, recreating code from this API to do the real job
behind the scenes.
The last word
First, you know that classes are objects that can create instances.
Well, in fact, classes are themselves instances. Of metaclasses.
>>> class Foo(object): pass
>>> id(Foo)
142630324
Everything is an object in Python, and they are all either instance of classes
or instances of metaclasses.
Except for type.
type is actually its own metaclass. This is not something you could
reproduce in pure Python, and is done by cheating a little bit at the implementation
level.
Secondly, metaclasses are complicated. You may not want to use them for
very simple class alterations. You can change classes by using two different techniques:
monkey patching
class decorators
99% of the time you need class alteration, you are better off using these.
But 98% of the time, you don't need class alteration at all.
A metaclass is the class of a class. A class defines how an instance of the class (i.e. an object) behaves while a metaclass defines how a class behaves. A class is an instance of a metaclass.
While in Python you can use arbitrary callables for metaclasses (like Jerub shows), the better approach is to make it an actual class itself. type is the usual metaclass in Python. type is itself a class, and it is its own type. You won't be able to recreate something like type purely in Python, but Python cheats a little. To create your own metaclass in Python you really just want to subclass type.
A metaclass is most commonly used as a class-factory. When you create an object by calling the class, Python creates a new class (when it executes the 'class' statement) by calling the metaclass. Combined with the normal __init__ and __new__ methods, metaclasses therefore allow you to do 'extra things' when creating a class, like registering the new class with some registry or replace the class with something else entirely.
When the class statement is executed, Python first executes the body of the class statement as a normal block of code. The resulting namespace (a dict) holds the attributes of the class-to-be. The metaclass is determined by looking at the baseclasses of the class-to-be (metaclasses are inherited), at the __metaclass__ attribute of the class-to-be (if any) or the __metaclass__ global variable. The metaclass is then called with the name, bases and attributes of the class to instantiate it.
However, metaclasses actually define the type of a class, not just a factory for it, so you can do much more with them. You can, for instance, define normal methods on the metaclass. These metaclass-methods are like classmethods in that they can be called on the class without an instance, but they are also not like classmethods in that they cannot be called on an instance of the class. type.__subclasses__() is an example of a method on the type metaclass. You can also define the normal 'magic' methods, like __add__, __iter__ and __getattr__, to implement or change how the class behaves.
Here's an aggregated example of the bits and pieces:
def make_hook(f):
"""Decorator to turn 'foo' method into '__foo__'"""
f.is_hook = 1
return f
class MyType(type):
def __new__(mcls, name, bases, attrs):
if name.startswith('None'):
return None
# Go over attributes and see if they should be renamed.
newattrs = {}
for attrname, attrvalue in attrs.iteritems():
if getattr(attrvalue, 'is_hook', 0):
newattrs['__%s__' % attrname] = attrvalue
else:
newattrs[attrname] = attrvalue
return super(MyType, mcls).__new__(mcls, name, bases, newattrs)
def __init__(self, name, bases, attrs):
super(MyType, self).__init__(name, bases, attrs)
# classregistry.register(self, self.interfaces)
print "Would register class %s now." % self
def __add__(self, other):
class AutoClass(self, other):
pass
return AutoClass
# Alternatively, to autogenerate the classname as well as the class:
# return type(self.__name__ + other.__name__, (self, other), {})
def unregister(self):
# classregistry.unregister(self)
print "Would unregister class %s now." % self
class MyObject:
__metaclass__ = MyType
class NoneSample(MyObject):
pass
# Will print "NoneType None"
print type(NoneSample), repr(NoneSample)
class Example(MyObject):
def __init__(self, value):
self.value = value
#make_hook
def add(self, other):
return self.__class__(self.value + other.value)
# Will unregister the class
Example.unregister()
inst = Example(10)
# Will fail with an AttributeError
#inst.unregister()
print inst + inst
class Sibling(MyObject):
pass
ExampleSibling = Example + Sibling
# ExampleSibling is now a subclass of both Example and Sibling (with no
# content of its own) although it will believe it's called 'AutoClass'
print ExampleSibling
print ExampleSibling.__mro__
Note, this answer is for Python 2.x as it was written in 2008, metaclasses are slightly different in 3.x.
Metaclasses are the secret sauce that make 'class' work. The default metaclass for a new style object is called 'type'.
class type(object)
| type(object) -> the object's type
| type(name, bases, dict) -> a new type
Metaclasses take 3 args. 'name', 'bases' and 'dict'
Here is where the secret starts. Look for where name, bases and the dict come from in this example class definition.
class ThisIsTheName(Bases, Are, Here):
All_the_code_here
def doesIs(create, a):
dict
Lets define a metaclass that will demonstrate how 'class:' calls it.
def test_metaclass(name, bases, dict):
print 'The Class Name is', name
print 'The Class Bases are', bases
print 'The dict has', len(dict), 'elems, the keys are', dict.keys()
return "yellow"
class TestName(object, None, int, 1):
__metaclass__ = test_metaclass
foo = 1
def baz(self, arr):
pass
print 'TestName = ', repr(TestName)
# output =>
The Class Name is TestName
The Class Bases are (<type 'object'>, None, <type 'int'>, 1)
The dict has 4 elems, the keys are ['baz', '__module__', 'foo', '__metaclass__']
TestName = 'yellow'
And now, an example that actually means something, this will automatically make the variables in the list "attributes" set on the class, and set to None.
def init_attributes(name, bases, dict):
if 'attributes' in dict:
for attr in dict['attributes']:
dict[attr] = None
return type(name, bases, dict)
class Initialised(object):
__metaclass__ = init_attributes
attributes = ['foo', 'bar', 'baz']
print 'foo =>', Initialised.foo
# output=>
foo => None
Note that the magic behaviour that Initialised gains by having the metaclass init_attributes is not passed onto a subclass of Initialised.
Here is an even more concrete example, showing how you can subclass 'type' to make a metaclass that performs an action when the class is created. This is quite tricky:
class MetaSingleton(type):
instance = None
def __call__(cls, *args, **kw):
if cls.instance is None:
cls.instance = super(MetaSingleton, cls).__call__(*args, **kw)
return cls.instance
class Foo(object):
__metaclass__ = MetaSingleton
a = Foo()
b = Foo()
assert a is b
Others have explained how metaclasses work and how they fit into the Python type system. Here's an example of what they can be used for. In a testing framework I wrote, I wanted to keep track of the order in which classes were defined, so that I could later instantiate them in this order. I found it easiest to do this using a metaclass.
class MyMeta(type):
counter = 0
def __init__(cls, name, bases, dic):
type.__init__(cls, name, bases, dic)
cls._order = MyMeta.counter
MyMeta.counter += 1
class MyType(object): # Python 2
__metaclass__ = MyMeta
class MyType(metaclass=MyMeta): # Python 3
pass
Anything that's a subclass of MyType then gets a class attribute _order that records the order in which the classes were defined.
One use for metaclasses is adding new properties and methods to an instance automatically.
For example, if you look at Django models, their definition looks a bit confusing. It looks as if you are only defining class properties:
class Person(models.Model):
first_name = models.CharField(max_length=30)
last_name = models.CharField(max_length=30)
However, at runtime the Person objects are filled with all sorts of useful methods. See the source for some amazing metaclassery.
I think the ONLamp introduction to metaclass programming is well written and gives a really good introduction to the topic despite being several years old already.
http://www.onlamp.com/pub/a/python/2003/04/17/metaclasses.html (archived at https://web.archive.org/web/20080206005253/http://www.onlamp.com/pub/a/python/2003/04/17/metaclasses.html)
In short: A class is a blueprint for the creation of an instance, a metaclass is a blueprint for the creation of a class. It can be easily seen that in Python classes need to be first-class objects too to enable this behavior.
I've never written one myself, but I think one of the nicest uses of metaclasses can be seen in the Django framework. The model classes use a metaclass approach to enable a declarative style of writing new models or form classes. While the metaclass is creating the class, all members get the possibility to customize the class itself.
Creating a new model
The metaclass enabling this
The thing that's left to say is: If you don't know what metaclasses are, the probability that you will not need them is 99%.
What are metaclasses? What do you use them for?
TLDR: A metaclass instantiates and defines behavior for a class just like a class instantiates and defines behavior for an instance.
Pseudocode:
>>> Class(...)
instance
The above should look familiar. Well, where does Class come from? It's an instance of a metaclass (also pseudocode):
>>> Metaclass(...)
Class
In real code, we can pass the default metaclass, type, everything we need to instantiate a class and we get a class:
>>> type('Foo', (object,), {}) # requires a name, bases, and a namespace
<class '__main__.Foo'>
Putting it differently
A class is to an instance as a metaclass is to a class.
When we instantiate an object, we get an instance:
>>> object() # instantiation of class
<object object at 0x7f9069b4e0b0> # instance
Likewise, when we define a class explicitly with the default metaclass, type, we instantiate it:
>>> type('Object', (object,), {}) # instantiation of metaclass
<class '__main__.Object'> # instance
Put another way, a class is an instance of a metaclass:
>>> isinstance(object, type)
True
Put a third way, a metaclass is a class's class.
>>> type(object) == type
True
>>> object.__class__
<class 'type'>
When you write a class definition and Python executes it, it uses a metaclass to instantiate the class object (which will, in turn, be used to instantiate instances of that class).
Just as we can use class definitions to change how custom object instances behave, we can use a metaclass class definition to change the way a class object behaves.
What can they be used for? From the docs:
The potential uses for metaclasses are boundless. Some ideas that have been explored include logging, interface checking, automatic delegation, automatic property creation, proxies, frameworks, and automatic resource locking/synchronization.
Nevertheless, it is usually encouraged for users to avoid using metaclasses unless absolutely necessary.
You use a metaclass every time you create a class:
When you write a class definition, for example, like this,
class Foo(object):
'demo'
You instantiate a class object.
>>> Foo
<class '__main__.Foo'>
>>> isinstance(Foo, type), isinstance(Foo, object)
(True, True)
It is the same as functionally calling type with the appropriate arguments and assigning the result to a variable of that name:
name = 'Foo'
bases = (object,)
namespace = {'__doc__': 'demo'}
Foo = type(name, bases, namespace)
Note, some things automatically get added to the __dict__, i.e., the namespace:
>>> Foo.__dict__
dict_proxy({'__dict__': <attribute '__dict__' of 'Foo' objects>,
'__module__': '__main__', '__weakref__': <attribute '__weakref__'
of 'Foo' objects>, '__doc__': 'demo'})
The metaclass of the object we created, in both cases, is type.
(A side-note on the contents of the class __dict__: __module__ is there because classes must know where they are defined, and __dict__ and __weakref__ are there because we don't define __slots__ - if we define __slots__ we'll save a bit of space in the instances, as we can disallow __dict__ and __weakref__ by excluding them. For example:
>>> Baz = type('Bar', (object,), {'__doc__': 'demo', '__slots__': ()})
>>> Baz.__dict__
mappingproxy({'__doc__': 'demo', '__slots__': (), '__module__': '__main__'})
... but I digress.)
We can extend type just like any other class definition:
Here's the default __repr__ of classes:
>>> Foo
<class '__main__.Foo'>
One of the most valuable things we can do by default in writing a Python object is to provide it with a good __repr__. When we call help(repr) we learn that there's a good test for a __repr__ that also requires a test for equality - obj == eval(repr(obj)). The following simple implementation of __repr__ and __eq__ for class instances of our type class provides us with a demonstration that may improve on the default __repr__ of classes:
class Type(type):
def __repr__(cls):
"""
>>> Baz
Type('Baz', (Foo, Bar,), {'__module__': '__main__', '__doc__': None})
>>> eval(repr(Baz))
Type('Baz', (Foo, Bar,), {'__module__': '__main__', '__doc__': None})
"""
metaname = type(cls).__name__
name = cls.__name__
parents = ', '.join(b.__name__ for b in cls.__bases__)
if parents:
parents += ','
namespace = ', '.join(': '.join(
(repr(k), repr(v) if not isinstance(v, type) else v.__name__))
for k, v in cls.__dict__.items())
return '{0}(\'{1}\', ({2}), {{{3}}})'.format(metaname, name, parents, namespace)
def __eq__(cls, other):
"""
>>> Baz == eval(repr(Baz))
True
"""
return (cls.__name__, cls.__bases__, cls.__dict__) == (
other.__name__, other.__bases__, other.__dict__)
So now when we create an object with this metaclass, the __repr__ echoed on the command line provides a much less ugly sight than the default:
>>> class Bar(object): pass
>>> Baz = Type('Baz', (Foo, Bar,), {'__module__': '__main__', '__doc__': None})
>>> Baz
Type('Baz', (Foo, Bar,), {'__module__': '__main__', '__doc__': None})
With a nice __repr__ defined for the class instance, we have a stronger ability to debug our code. However, much further checking with eval(repr(Class)) is unlikely (as functions would be rather impossible to eval from their default __repr__'s).
An expected usage: __prepare__ a namespace
If, for example, we want to know in what order a class's methods are created in, we could provide an ordered dict as the namespace of the class. We would do this with __prepare__ which returns the namespace dict for the class if it is implemented in Python 3:
from collections import OrderedDict
class OrderedType(Type):
#classmethod
def __prepare__(metacls, name, bases, **kwargs):
return OrderedDict()
def __new__(cls, name, bases, namespace, **kwargs):
result = Type.__new__(cls, name, bases, dict(namespace))
result.members = tuple(namespace)
return result
And usage:
class OrderedMethodsObject(object, metaclass=OrderedType):
def method1(self): pass
def method2(self): pass
def method3(self): pass
def method4(self): pass
And now we have a record of the order in which these methods (and other class attributes) were created:
>>> OrderedMethodsObject.members
('__module__', '__qualname__', 'method1', 'method2', 'method3', 'method4')
Note, this example was adapted from the documentation - the new enum in the standard library does this.
So what we did was instantiate a metaclass by creating a class. We can also treat the metaclass as we would any other class. It has a method resolution order:
>>> inspect.getmro(OrderedType)
(<class '__main__.OrderedType'>, <class '__main__.Type'>, <class 'type'>, <class 'object'>)
And it has approximately the correct repr (which we can no longer eval unless we can find a way to represent our functions.):
>>> OrderedMethodsObject
OrderedType('OrderedMethodsObject', (object,), {'method1': <function OrderedMethodsObject.method1 at 0x0000000002DB01E0>, 'members': ('__module__', '__qualname__', 'method1', 'method2', 'method3', 'method4'), 'method3': <function OrderedMet
hodsObject.method3 at 0x0000000002DB02F0>, 'method2': <function OrderedMethodsObject.method2 at 0x0000000002DB0268>, '__module__': '__main__', '__weakref__': <attribute '__weakref__' of 'OrderedMethodsObject' objects>, '__doc__': None, '__d
ict__': <attribute '__dict__' of 'OrderedMethodsObject' objects>, 'method4': <function OrderedMethodsObject.method4 at 0x0000000002DB0378>})
Python 3 update
There are (at this point) two key methods in a metaclass:
__prepare__, and
__new__
__prepare__ lets you supply a custom mapping (such as an OrderedDict) to be used as the namespace while the class is being created. You must return an instance of whatever namespace you choose. If you don't implement __prepare__ a normal dict is used.
__new__ is responsible for the actual creation/modification of the final class.
A bare-bones, do-nothing-extra metaclass would like:
class Meta(type):
def __prepare__(metaclass, cls, bases):
return dict()
def __new__(metacls, cls, bases, clsdict):
return super().__new__(metacls, cls, bases, clsdict)
A simple example:
Say you want some simple validation code to run on your attributes -- like it must always be an int or a str. Without a metaclass, your class would look something like:
class Person:
weight = ValidateType('weight', int)
age = ValidateType('age', int)
name = ValidateType('name', str)
As you can see, you have to repeat the name of the attribute twice. This makes typos possible along with irritating bugs.
A simple metaclass can address that problem:
class Person(metaclass=Validator):
weight = ValidateType(int)
age = ValidateType(int)
name = ValidateType(str)
This is what the metaclass would look like (not using __prepare__ since it is not needed):
class Validator(type):
def __new__(metacls, cls, bases, clsdict):
# search clsdict looking for ValidateType descriptors
for name, attr in clsdict.items():
if isinstance(attr, ValidateType):
attr.name = name
attr.attr = '_' + name
# create final class and return it
return super().__new__(metacls, cls, bases, clsdict)
A sample run of:
p = Person()
p.weight = 9
print(p.weight)
p.weight = '9'
produces:
9
Traceback (most recent call last):
File "simple_meta.py", line 36, in <module>
p.weight = '9'
File "simple_meta.py", line 24, in __set__
(self.name, self.type, value))
TypeError: weight must be of type(s) <class 'int'> (got '9')
Note: This example is simple enough it could have also been accomplished with a class decorator, but presumably an actual metaclass would be doing much more.
The 'ValidateType' class for reference:
class ValidateType:
def __init__(self, type):
self.name = None # will be set by metaclass
self.attr = None # will be set by metaclass
self.type = type
def __get__(self, inst, cls):
if inst is None:
return self
else:
return inst.__dict__[self.attr]
def __set__(self, inst, value):
if not isinstance(value, self.type):
raise TypeError('%s must be of type(s) %s (got %r)' %
(self.name, self.type, value))
else:
inst.__dict__[self.attr] = value
Role of a metaclass' __call__() method when creating a class instance
If you've done Python programming for more than a few months you'll eventually stumble upon code that looks like this:
# define a class
class SomeClass(object):
# ...
# some definition here ...
# ...
# create an instance of it
instance = SomeClass()
# then call the object as if it's a function
result = instance('foo', 'bar')
The latter is possible when you implement the __call__() magic method on the class.
class SomeClass(object):
# ...
# some definition here ...
# ...
def __call__(self, foo, bar):
return bar + foo
The __call__() method is invoked when an instance of a class is used as a callable. But as we've seen from previous answers a class itself is an instance of a metaclass, so when we use the class as a callable (i.e. when we create an instance of it) we're actually calling its metaclass' __call__() method. At this point most Python programmers are a bit confused because they've been told that when creating an instance like this instance = SomeClass() you're calling its __init__() method. Some who've dug a bit deeper know that before __init__() there's __new__(). Well, today another layer of truth is being revealed, before __new__() there's the metaclass' __call__().
Let's study the method call chain from specifically the perspective of creating an instance of a class.
This is a metaclass that logs exactly the moment before an instance is created and the moment it's about to return it.
class Meta_1(type):
def __call__(cls):
print "Meta_1.__call__() before creating an instance of ", cls
instance = super(Meta_1, cls).__call__()
print "Meta_1.__call__() about to return instance."
return instance
This is a class that uses that metaclass
class Class_1(object):
__metaclass__ = Meta_1
def __new__(cls):
print "Class_1.__new__() before creating an instance."
instance = super(Class_1, cls).__new__(cls)
print "Class_1.__new__() about to return instance."
return instance
def __init__(self):
print "entering Class_1.__init__() for instance initialization."
super(Class_1,self).__init__()
print "exiting Class_1.__init__()."
And now let's create an instance of Class_1
instance = Class_1()
# Meta_1.__call__() before creating an instance of <class '__main__.Class_1'>.
# Class_1.__new__() before creating an instance.
# Class_1.__new__() about to return instance.
# entering Class_1.__init__() for instance initialization.
# exiting Class_1.__init__().
# Meta_1.__call__() about to return instance.
Observe that the code above doesn't actually do anything more than logging the tasks. Each method delegates the actual work to its parent's implementation, thus keeping the default behavior. Since type is Meta_1's parent class (type being the default parent metaclass) and considering the ordering sequence of the output above, we now have a clue as to what would be the pseudo implementation of type.__call__():
class type:
def __call__(cls, *args, **kwarg):
# ... maybe a few things done to cls here
# then we call __new__() on the class to create an instance
instance = cls.__new__(cls, *args, **kwargs)
# ... maybe a few things done to the instance here
# then we initialize the instance with its __init__() method
instance.__init__(*args, **kwargs)
# ... maybe a few more things done to instance here
# then we return it
return instance
We can see that the metaclass' __call__() method is the one that's called first. It then delegates creation of the instance to the class's __new__() method and initialization to the instance's __init__(). It's also the one that ultimately returns the instance.
From the above it stems that the metaclass' __call__() is also given the opportunity to decide whether or not a call to Class_1.__new__() or Class_1.__init__() will eventually be made. Over the course of its execution it could actually return an object that hasn't been touched by either of these methods. Take for example this approach to the singleton pattern:
class Meta_2(type):
singletons = {}
def __call__(cls, *args, **kwargs):
if cls in Meta_2.singletons:
# we return the only instance and skip a call to __new__()
# and __init__()
print ("{} singleton returning from Meta_2.__call__(), "
"skipping creation of new instance.".format(cls))
return Meta_2.singletons[cls]
# else if the singleton isn't present we proceed as usual
print "Meta_2.__call__() before creating an instance."
instance = super(Meta_2, cls).__call__(*args, **kwargs)
Meta_2.singletons[cls] = instance
print "Meta_2.__call__() returning new instance."
return instance
class Class_2(object):
__metaclass__ = Meta_2
def __new__(cls, *args, **kwargs):
print "Class_2.__new__() before creating instance."
instance = super(Class_2, cls).__new__(cls)
print "Class_2.__new__() returning instance."
return instance
def __init__(self, *args, **kwargs):
print "entering Class_2.__init__() for initialization."
super(Class_2, self).__init__()
print "exiting Class_2.__init__()."
Let's observe what happens when repeatedly trying to create an object of type Class_2
a = Class_2()
# Meta_2.__call__() before creating an instance.
# Class_2.__new__() before creating instance.
# Class_2.__new__() returning instance.
# entering Class_2.__init__() for initialization.
# exiting Class_2.__init__().
# Meta_2.__call__() returning new instance.
b = Class_2()
# <class '__main__.Class_2'> singleton returning from Meta_2.__call__(), skipping creation of new instance.
c = Class_2()
# <class '__main__.Class_2'> singleton returning from Meta_2.__call__(), skipping creation of new instance.
a is b is c # True
A metaclass is a class that tells how (some) other class should be created.
This is a case where I saw metaclass as a solution to my problem:
I had a really complicated problem, that probably could have been solved differently, but I chose to solve it using a metaclass. Because of the complexity, it is one of the few modules I have written where the comments in the module surpass the amount of code that has been written. Here it is...
#!/usr/bin/env python
# Copyright (C) 2013-2014 Craig Phillips. All rights reserved.
# This requires some explaining. The point of this metaclass excercise is to
# create a static abstract class that is in one way or another, dormant until
# queried. I experimented with creating a singlton on import, but that did
# not quite behave how I wanted it to. See now here, we are creating a class
# called GsyncOptions, that on import, will do nothing except state that its
# class creator is GsyncOptionsType. This means, docopt doesn't parse any
# of the help document, nor does it start processing command line options.
# So importing this module becomes really efficient. The complicated bit
# comes from requiring the GsyncOptions class to be static. By that, I mean
# any property on it, may or may not exist, since they are not statically
# defined; so I can't simply just define the class with a whole bunch of
# properties that are #property #staticmethods.
#
# So here's how it works:
#
# Executing 'from libgsync.options import GsyncOptions' does nothing more
# than load up this module, define the Type and the Class and import them
# into the callers namespace. Simple.
#
# Invoking 'GsyncOptions.debug' for the first time, or any other property
# causes the __metaclass__ __getattr__ method to be called, since the class
# is not instantiated as a class instance yet. The __getattr__ method on
# the type then initialises the class (GsyncOptions) via the __initialiseClass
# method. This is the first and only time the class will actually have its
# dictionary statically populated. The docopt module is invoked to parse the
# usage document and generate command line options from it. These are then
# paired with their defaults and what's in sys.argv. After all that, we
# setup some dynamic properties that could not be defined by their name in
# the usage, before everything is then transplanted onto the actual class
# object (or static class GsyncOptions).
#
# Another piece of magic, is to allow command line options to be set in
# in their native form and be translated into argparse style properties.
#
# Finally, the GsyncListOptions class is actually where the options are
# stored. This only acts as a mechanism for storing options as lists, to
# allow aggregation of duplicate options or options that can be specified
# multiple times. The __getattr__ call hides this by default, returning the
# last item in a property's list. However, if the entire list is required,
# calling the 'list()' method on the GsyncOptions class, returns a reference
# to the GsyncListOptions class, which contains all of the same properties
# but as lists and without the duplication of having them as both lists and
# static singlton values.
#
# So this actually means that GsyncOptions is actually a static proxy class...
#
# ...And all this is neatly hidden within a closure for safe keeping.
def GetGsyncOptionsType():
class GsyncListOptions(object):
__initialised = False
class GsyncOptionsType(type):
def __initialiseClass(cls):
if GsyncListOptions._GsyncListOptions__initialised: return
from docopt import docopt
from libgsync.options import doc
from libgsync import __version__
options = docopt(
doc.__doc__ % __version__,
version = __version__,
options_first = True
)
paths = options.pop('<path>', None)
setattr(cls, "destination_path", paths.pop() if paths else None)
setattr(cls, "source_paths", paths)
setattr(cls, "options", options)
for k, v in options.iteritems():
setattr(cls, k, v)
GsyncListOptions._GsyncListOptions__initialised = True
def list(cls):
return GsyncListOptions
def __getattr__(cls, name):
cls.__initialiseClass()
return getattr(GsyncListOptions, name)[-1]
def __setattr__(cls, name, value):
# Substitut option names: --an-option-name for an_option_name
import re
name = re.sub(r'^__', "", re.sub(r'-', "_", name))
listvalue = []
# Ensure value is converted to a list type for GsyncListOptions
if isinstance(value, list):
if value:
listvalue = [] + value
else:
listvalue = [ None ]
else:
listvalue = [ value ]
type.__setattr__(GsyncListOptions, name, listvalue)
# Cleanup this module to prevent tinkering.
import sys
module = sys.modules[__name__]
del module.__dict__['GetGsyncOptionsType']
return GsyncOptionsType
# Our singlton abstract proxy class.
class GsyncOptions(object):
__metaclass__ = GetGsyncOptionsType()
The tl;dr version
The type(obj) function gets you the type of an object.
The type() of a class is its metaclass.
To use a metaclass:
class Foo(object):
__metaclass__ = MyMetaClass
type is its own metaclass. The class of a class is a metaclass-- the body of a class is the arguments passed to the metaclass that is used to construct the class.
Here you can read about how to use metaclasses to customize class construction.
type is actually a metaclass -- a class that creates another classes.
Most metaclass are the subclasses of type. The metaclass receives the new class as its first argument and provide access to class object with details as mentioned below:
>>> class MetaClass(type):
... def __init__(cls, name, bases, attrs):
... print ('class name: %s' %name )
... print ('Defining class %s' %cls)
... print('Bases %s: ' %bases)
... print('Attributes')
... for (name, value) in attrs.items():
... print ('%s :%r' %(name, value))
...
>>> class NewClass(object, metaclass=MetaClass):
... get_choch='dairy'
...
class name: NewClass
Bases <class 'object'>:
Defining class <class 'NewClass'>
get_choch :'dairy'
__module__ :'builtins'
__qualname__ :'NewClass'
Note:
Notice that the class was not instantiated at any time; the simple act of creating the class triggered execution of the metaclass.
Python classes are themselves objects - as in instance - of their meta-class.
The default metaclass, which is applied when when you determine classes as:
class foo:
...
meta class are used to apply some rule to an entire set of classes. For example, suppose you're building an ORM to access a database, and you want records from each table to be of a class mapped to that table (based on fields, business rules, etc..,), a possible use of metaclass is for instance, connection pool logic, which is share by all classes of record from all tables. Another use is logic to to support foreign keys, which involves multiple classes of records.
when you define metaclass, you subclass type, and can overrided the following magic methods to insert your logic.
class somemeta(type):
__new__(mcs, name, bases, clsdict):
"""
mcs: is the base metaclass, in this case type.
name: name of the new class, as provided by the user.
bases: tuple of base classes
clsdict: a dictionary containing all methods and attributes defined on class
you must return a class object by invoking the __new__ constructor on the base metaclass.
ie:
return type.__call__(mcs, name, bases, clsdict).
in the following case:
class foo(baseclass):
__metaclass__ = somemeta
an_attr = 12
def bar(self):
...
#classmethod
def foo(cls):
...
arguments would be : ( somemeta, "foo", (baseclass, baseofbase,..., object), {"an_attr":12, "bar": <function>, "foo": <bound class method>}
you can modify any of these values before passing on to type
"""
return type.__call__(mcs, name, bases, clsdict)
def __init__(self, name, bases, clsdict):
"""
called after type has been created. unlike in standard classes, __init__ method cannot modify the instance (cls) - and should be used for class validaton.
"""
pass
def __prepare__():
"""
returns a dict or something that can be used as a namespace.
the type will then attach methods and attributes from class definition to it.
call order :
somemeta.__new__ -> type.__new__ -> type.__init__ -> somemeta.__init__
"""
return dict()
def mymethod(cls):
""" works like a classmethod, but for class objects. Also, my method will not be visible to instances of cls.
"""
pass
anyhow, those two are the most commonly used hooks. metaclassing is powerful, and above is nowhere near and exhaustive list of uses for metaclassing.
The type() function can return the type of an object or create a new type,
for example, we can create a Hi class with the type() function and do not need to use this way with class Hi(object):
def func(self, name='mike'):
print('Hi, %s.' % name)
Hi = type('Hi', (object,), dict(hi=func))
h = Hi()
h.hi()
Hi, mike.
type(Hi)
type
type(h)
__main__.Hi
In addition to using type() to create classes dynamically, you can control creation behavior of class and use metaclass.
According to the Python object model, the class is the object, so the class must be an instance of another certain class.
By default, a Python class is instance of the type class. That is, type is metaclass of most of the built-in classes and metaclass of user-defined classes.
class ListMetaclass(type):
def __new__(cls, name, bases, attrs):
attrs['add'] = lambda self, value: self.append(value)
return type.__new__(cls, name, bases, attrs)
class CustomList(list, metaclass=ListMetaclass):
pass
lst = CustomList()
lst.add('custom_list_1')
lst.add('custom_list_2')
lst
['custom_list_1', 'custom_list_2']
Magic will take effect when we passed keyword arguments in metaclass, it indicates the Python interpreter to create the CustomList through ListMetaclass. new (), at this point, we can modify the class definition, for example, and add a new method and then return the revised definition.
In addition to the published answers I can say that a metaclass defines the behaviour for a class. So, you can explicitly set your metaclass. Whenever Python gets a keyword class then it starts searching for the metaclass. If it's not found – the default metaclass type is used to create the class's object. Using the __metaclass__ attribute, you can set metaclass of your class:
class MyClass:
__metaclass__ = type
# write here other method
# write here one more method
print(MyClass.__metaclass__)
It'll produce the output like this:
class 'type'
And, of course, you can create your own metaclass to define the behaviour of any class that are created using your class.
For doing that, your default metaclass type class must be inherited as this is the main metaclass:
class MyMetaClass(type):
__metaclass__ = type
# you can write here any behaviour you want
class MyTestClass:
__metaclass__ = MyMetaClass
Obj = MyTestClass()
print(Obj.__metaclass__)
print(MyMetaClass.__metaclass__)
The output will be:
class '__main__.MyMetaClass'
class 'type'
Note that in python 3.6 a new dunder method __init_subclass__(cls, **kwargs) was introduced to replace a lot of common use cases for metaclasses. Is is called when a subclass of the defining class is created. See python docs.
Here's another example of what it can be used for:
You can use the metaclass to change the function of its instance (the class).
class MetaMemberControl(type):
__slots__ = ()
#classmethod
def __prepare__(mcs, f_cls_name, f_cls_parents, # f_cls means: future class
meta_args=None, meta_options=None): # meta_args and meta_options is not necessarily needed, just so you know.
f_cls_attr = dict()
if not "do something or if you want to define your cool stuff of dict...":
return dict(make_your_special_dict=None)
else:
return f_cls_attr
def __new__(mcs, f_cls_name, f_cls_parents, f_cls_attr,
meta_args=None, meta_options=None):
original_getattr = f_cls_attr.get('__getattribute__')
original_setattr = f_cls_attr.get('__setattr__')
def init_getattr(self, item):
if not item.startswith('_'): # you can set break points at here
alias_name = '_' + item
if alias_name in f_cls_attr['__slots__']:
item = alias_name
if original_getattr is not None:
return original_getattr(self, item)
else:
return super(eval(f_cls_name), self).__getattribute__(item)
def init_setattr(self, key, value):
if not key.startswith('_') and ('_' + key) in f_cls_attr['__slots__']:
raise AttributeError(f"you can't modify private members:_{key}")
if original_setattr is not None:
original_setattr(self, key, value)
else:
super(eval(f_cls_name), self).__setattr__(key, value)
f_cls_attr['__getattribute__'] = init_getattr
f_cls_attr['__setattr__'] = init_setattr
cls = super().__new__(mcs, f_cls_name, f_cls_parents, f_cls_attr)
return cls
class Human(metaclass=MetaMemberControl):
__slots__ = ('_age', '_name')
def __init__(self, name, age):
self._name = name
self._age = age
def __getattribute__(self, item):
"""
is just for IDE recognize.
"""
return super().__getattribute__(item)
""" with MetaMemberControl then you don't have to write as following
#property
def name(self):
return self._name
#property
def age(self):
return self._age
"""
def test_demo():
human = Human('Carson', 27)
# human.age = 18 # you can't modify private members:_age <-- this is defined by yourself.
# human.k = 18 # 'Human' object has no attribute 'k' <-- system error.
age1 = human._age # It's OK, although the IDE will show some warnings. (Access to a protected member _age of a class)
age2 = human.age # It's OK! see below:
"""
if you do not define `__getattribute__` at the class of Human,
the IDE will show you: Unresolved attribute reference 'age' for class 'Human'
but it's ok on running since the MetaMemberControl will help you.
"""
if __name__ == '__main__':
test_demo()
The metaclass is powerful, there are many things (such as monkey magic) you can do with it, but be careful this may only be known to you.
The top answer is correct.
But readers may be coming here searching answers about similarly named inner classes. They are present in popular libraries, such as Django and WTForms.
As DavidW points out in the comments beneath this answer, these are library-specific features and are not to be confused with the advanced, unrelated Python language feature with a similar name.
Rather, these are namespaces within classes' dicts. They are constructed using inner classes for sake of readability.
In this example special field, abstract is visibly separate from fields of Author model.
from django.db import models
class Author(models.Model):
name = models.CharField(max_length=50)
email = models.EmailField()
class Meta:
abstract = True
Another example is from the documentation for WTForms:
from wtforms.form import Form
from wtforms.csrf.session import SessionCSRF
from wtforms.fields import StringField
class MyBaseForm(Form):
class Meta:
csrf = True
csrf_class = SessionCSRF
name = StringField("name")
This syntax does not get special treatment in the python programming language. Meta is not a keyword here, and does not trigger metaclass behavior. Rather, third-party library code in packages like Django and WTForms reads this property in the constructors of certain classes, and elsewhere.
The presence of these declarations modifies the behavior of the classes that have these declarations. For example, WTForms reads self.Meta.csrf to determine if the form needs a csrf field.
In object-oriented programming, a metaclass is a class whose instances are classes. Just as an ordinary class defines the behavior of certain objects, a metaclass defines the behavior of certain class and their instances
The term metaclass simply means something used to create classes. In other words, it is the class of a class. The metaclass is used to create the class so like the object being an instance of a class, a class is an instance of a metaclass. In python classes are also considered objects.
A class, in Python, is an object, and just like any other object, it is an instance of "something". This "something" is what is termed as a Metaclass. This metaclass is a special type of class that creates other class's objects. Hence, metaclass is responsible for making new classes. This allows the programmer to customize the way classes are generated.
To create a metaclass, overriding of new() and init() methods is usually done. new() can be overridden to change the way objects are created, while init() can be overridden to change the way of initializing the object. Metaclass can be created by a number of ways. One of the ways is to use type() function. type() function, when called with 3 parameters, creates a metaclass. The parameters are :-
Class Name
Tuple having base classes inherited by class
A dictionary having all class methods and class variables
Another way of creating a metaclass comprises of 'metaclass' keyword. Define the metaclass as a simple class. In the parameters of inherited class, pass metaclass=metaclass_name
Metaclass can be specifically used in the following situations :-
when a particular effect has to be applied to all the subclasses
Automatic change of class (on creation) is required
By API developers
I saw an interesting use case for metaclasses in a package called classutilities. It checks if all class variables are in upper case format (it is convenient to have unified logic for configuration classes), and checks if there are no instance level methods in class.
Another interesting example for metaclases was deactivation of unittests based on complex conditions (checking values of multiple environmental variables).
In Python, a metaclass is a subclass of a subclass that determines how a subclass behaves. A class is an instance of another metaclass. In Python, a class specifies how the class's instance will behave.
Since metaclasses are in charge of class generation, you can write your own custom metaclasses to change how classes are created by performing additional actions or injecting code. Custom metaclasses aren't always important, but they can be.
look this:
Python 3.10.0rc2 (tags/v3.10.0rc2:839d789, Sep 7 2021, 18:51:45) [MSC v.1929 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> class Object:
... pass
...
>>> class Meta(type):
... test = 'Worked!!!'
... def __repr__(self):
... return 'This is "Meta" metaclass'
...
>>> class ObjectWithMetaClass(metaclass=Meta):
... pass
...
>>> Object or type(Object())
<class '__main__.Object'>
>>> ObjectWithMetaClass or type(ObjectWithMetaClass())
This is "Meta" metaclass
>>> Object.test
AttributeError: ...
>>> ObjectWithMetaClass.test
'Worked!!!'
>>> type(Object)
<class 'type'>
>>> type(ObjectWithMetaClass)
<class '__main__.Meta'>
>>> type(type(ObjectWithMetaClass))
<class 'type'>
>>> Object.__bases__
(<class 'object'>,)
>>> ObjectWithMetaClass.__bases__
(<class 'object'>,)
>>> type(ObjectWithMetaClass).__bases__
(<class 'type'>,)
>>> Object.__mro__
(<class '__main__.Object'>, <class 'object'>)
>>> ObjectWithMetaClass.__mro__
(This is "Meta" metaclass, <class 'object'>)
>>>
In other words, when an object was not created (type of object), we looking MetaClass.
i want to add a little on why type.__new__() over type()
first, take a look at these classes
In [1]: class MyMeta(type):
...: def __new__(cls, cls_name, bases, attrs):
...: print(cls, cls_name, bases, attrs)
...: return super().__new__(cls, cls_name, bases, attrs)
...:
In [2]: class AClass(metaclass=MyMeta):
...: pass
...:
<class '__main__.MyMeta'> AClass () {'__module__': '__main__', '__qualname__': 'AClass'}
In [3]: class BClass:
...: pass
...:
In [4]: AClass.__class__
Out[4]: __main__.MyMeta
In [5]: BClass.__class__
Out[5]: type
In [6]: class SubAClass(AClass):
...: pass
...:
<class '__main__.MyMeta'> SubAClass (<class '__main__.AClass'>,) {'__module__': '__main__', '__qualname__': 'SubAClass'}
when we were trying to create SubAClass a subclass of AClass, Python would take a look at the metaclass we designated to be used to create SubAClass
and in this case, we did not pass a metaclass for SubAClass, so Python got a None for metaclass.
and Python would try to pick up the first base class of SubAClass, which is AClass, has a metaclass, which is MyMeta, then it would call MyMeta.__new__ to create SubAClass
for simplicity, we can say
type.__new__ just assigned our metaclass to the parent.__class__(AClass.__class__).
and when a subclass was defined(SubAClass) by class statement, Python
would just use the parent.__class__ to create that subclass unless
we've manually passed a metaclass to our subclass
apparently, if you called type() instead of type.__new__, the class
would have type as its __class__ attr.
that means AClass would be equivalent of BClass, both of them have type
as their __class__ attr
how the searching of metaclass works in C code?
it works pretty much like what we've just mentioned
the function builtin___build_class__ would be called when you defined a class
and code is just so straightforward
static PyObject *
builtin___build_class__(PyObject *self, PyObject *const *args, Py_ssize_t nargs,
PyObject *kwnames){
if (meta == NULL) {
/* if there are no bases, use type: */
if (PyTuple_GET_SIZE(bases) == 0) {
meta = (PyObject *) (&PyType_Type);
}
/* else get the type of the first base */
else {
PyObject *base0 = PyTuple_GET_ITEM(bases, 0);
meta = (PyObject *)Py_TYPE(base0);
}
Py_INCREF(meta);
isclass = 1; /* meta is really a class */
}
PyObject *margs[3] = {name, bases, ns};
cls = PyObject_VectorcallDict(meta, margs, 3, mkw);
}
basically, meta = (PyObject *)Py_TYPE(base0); is everything we want to know
it can be translated to be
meta = MyMeta = AClass.__class__ = Py_TYPE(AClass)
In Python or in any other language we have a type for every variable or object we declare. For getting type of anything(variable,object,etc.) in Python we can use type() function.
Bypassing the metaclass keyword in the class definition we can customize the class creation process.
class meta(type):
pass
class baseclass(metaclass=meta): # This is Mestaclass
pass
class derivedclass(baseclass):
pass
print(type(meta))
print(type(baseclass))
print(type(derivedclass))
When defining a new class if no metaclass is defined the default type metaclass is used. If a given metaclass is not the object(instance) of type(), in that situation it is used directly as a metaclass.

What are metaclasses in Python?

What are metaclasses? What are they used for?
Classes as objects
Before understanding metaclasses, it helps to understand Python classes more deeply. Python has a very peculiar idea of what classes are, which it borrows from the Smalltalk language.
In most languages, classes are just pieces of code that describe how to produce an object. That is somewhat true in Python too:
>>> class ObjectCreator(object):
... pass
>>> my_object = ObjectCreator()
>>> print(my_object)
<__main__.ObjectCreator object at 0x8974f2c>
But classes are more than that in Python. Classes are objects too.
Yes, objects.
When a Python script runs, every line of code is executed from top to bottom. When the Python interpreter encounters the class keyword, Python creates an object out of the "description" of the class that follows. Thus, the following instruction
>>> class ObjectCreator(object):
... pass
...creates an object with the name ObjectCreator!
This object (the class) is itself capable of creating objects (called instances).
But still, it's an object. Therefore, like all objects:
you can assign it to a variable1
JustAnotherVariable = ObjectCreator
you can attach attributes to it
ObjectCreator.class_attribute = 'foo'
you can pass it as a function parameter
print(ObjectCreator)
1 Note that merely assigning it to another variable doesn't change the class's __name__, i.e.,
>>> print(JustAnotherVariable)
<class '__main__.ObjectCreator'>
>>> print(JustAnotherVariable())
<__main__.ObjectCreator object at 0x8997b4c>
Creating classes dynamically
Since classes are objects, you can create them on the fly, like any object.
First, you can create a class in a function using class:
>>> def choose_class(name):
... if name == 'foo':
... class Foo(object):
... pass
... return Foo # return the class, not an instance
... else:
... class Bar(object):
... pass
... return Bar
...
>>> MyClass = choose_class('foo')
>>> print(MyClass) # the function returns a class, not an instance
<class '__main__.Foo'>
>>> print(MyClass()) # you can create an object from this class
<__main__.Foo object at 0x89c6d4c>
But it's not so dynamic, since you still have to write the whole class yourself.
Since classes are objects, they must be generated by something.
When you use the class keyword, Python creates this object automatically. But as
with most things in Python, it gives you a way to do it manually.
Remember the function type? The good old function that lets you know what
type an object is:
>>> print(type(1))
<type 'int'>
>>> print(type("1"))
<type 'str'>
>>> print(type(ObjectCreator))
<type 'type'>
>>> print(type(ObjectCreator()))
<class '__main__.ObjectCreator'>
Well, type has also a completely different ability: it can create classes on the fly. type can take the description of a class as parameters,
and return a class.
(I know, it's silly that the same function can have two completely different uses according to the parameters you pass to it. It's an issue due to backward
compatibility in Python)
type works this way:
type(name, bases, attrs)
Where:
name: name of the class
bases: tuple of the parent class (for inheritance, can be empty)
attrs: dictionary containing attributes names and values
e.g.:
>>> class MyShinyClass(object):
... pass
can be created manually this way:
>>> MyShinyClass = type('MyShinyClass', (), {}) # returns a class object
>>> print(MyShinyClass)
<class '__main__.MyShinyClass'>
>>> print(MyShinyClass()) # create an instance with the class
<__main__.MyShinyClass object at 0x8997cec>
You'll notice that we use MyShinyClass as the name of the class
and as the variable to hold the class reference. They can be different,
but there is no reason to complicate things.
type accepts a dictionary to define the attributes of the class. So:
>>> class Foo(object):
... bar = True
Can be translated to:
>>> Foo = type('Foo', (), {'bar':True})
And used as a normal class:
>>> print(Foo)
<class '__main__.Foo'>
>>> print(Foo.bar)
True
>>> f = Foo()
>>> print(f)
<__main__.Foo object at 0x8a9b84c>
>>> print(f.bar)
True
And of course, you can inherit from it, so:
>>> class FooChild(Foo):
... pass
would be:
>>> FooChild = type('FooChild', (Foo,), {})
>>> print(FooChild)
<class '__main__.FooChild'>
>>> print(FooChild.bar) # bar is inherited from Foo
True
Eventually, you'll want to add methods to your class. Just define a function
with the proper signature and assign it as an attribute.
>>> def echo_bar(self):
... print(self.bar)
...
>>> FooChild = type('FooChild', (Foo,), {'echo_bar': echo_bar})
>>> hasattr(Foo, 'echo_bar')
False
>>> hasattr(FooChild, 'echo_bar')
True
>>> my_foo = FooChild()
>>> my_foo.echo_bar()
True
And you can add even more methods after you dynamically create the class, just like adding methods to a normally created class object.
>>> def echo_bar_more(self):
... print('yet another method')
...
>>> FooChild.echo_bar_more = echo_bar_more
>>> hasattr(FooChild, 'echo_bar_more')
True
You see where we are going: in Python, classes are objects, and you can create a class on the fly, dynamically.
This is what Python does when you use the keyword class, and it does so by using a metaclass.
What are metaclasses (finally)
Metaclasses are the 'stuff' that creates classes.
You define classes in order to create objects, right?
But we learned that Python classes are objects.
Well, metaclasses are what create these objects. They are the classes' classes,
you can picture them this way:
MyClass = MetaClass()
my_object = MyClass()
You've seen that type lets you do something like this:
MyClass = type('MyClass', (), {})
It's because the function type is in fact a metaclass. type is the
metaclass Python uses to create all classes behind the scenes.
Now you wonder "why the heck is it written in lowercase, and not Type?"
Well, I guess it's a matter of consistency with str, the class that creates
strings objects, and int the class that creates integer objects. type is
just the class that creates class objects.
You see that by checking the __class__ attribute.
Everything, and I mean everything, is an object in Python. That includes integers,
strings, functions and classes. All of them are objects. And all of them have
been created from a class:
>>> age = 35
>>> age.__class__
<type 'int'>
>>> name = 'bob'
>>> name.__class__
<type 'str'>
>>> def foo(): pass
>>> foo.__class__
<type 'function'>
>>> class Bar(object): pass
>>> b = Bar()
>>> b.__class__
<class '__main__.Bar'>
Now, what is the __class__ of any __class__ ?
>>> age.__class__.__class__
<type 'type'>
>>> name.__class__.__class__
<type 'type'>
>>> foo.__class__.__class__
<type 'type'>
>>> b.__class__.__class__
<type 'type'>
So, a metaclass is just the stuff that creates class objects.
You can call it a 'class factory' if you wish.
type is the built-in metaclass Python uses, but of course, you can create your
own metaclass.
The __metaclass__ attribute
In Python 2, you can add a __metaclass__ attribute when you write a class (see next section for the Python 3 syntax):
class Foo(object):
__metaclass__ = something...
[...]
If you do so, Python will use the metaclass to create the class Foo.
Careful, it's tricky.
You write class Foo(object) first, but the class object Foo is not created
in memory yet.
Python will look for __metaclass__ in the class definition. If it finds it,
it will use it to create the object class Foo. If it doesn't, it will use
type to create the class.
Read that several times.
When you do:
class Foo(Bar):
pass
Python does the following:
Is there a __metaclass__ attribute in Foo?
If yes, create in-memory a class object (I said a class object, stay with me here), with the name Foo by using what is in __metaclass__.
If Python can't find __metaclass__, it will look for a __metaclass__ at the MODULE level, and try to do the same (but only for classes that don't inherit anything, basically old-style classes).
Then if it can't find any __metaclass__ at all, it will use the Bar's (the first parent) own metaclass (which might be the default type) to create the class object.
Be careful here that the __metaclass__ attribute will not be inherited, the metaclass of the parent (Bar.__class__) will be. If Bar used a __metaclass__ attribute that created Bar with type() (and not type.__new__()), the subclasses will not inherit that behavior.
Now the big question is, what can you put in __metaclass__?
The answer is something that can create a class.
And what can create a class? type, or anything that subclasses or uses it.
Metaclasses in Python 3
The syntax to set the metaclass has been changed in Python 3:
class Foo(object, metaclass=something):
...
i.e. the __metaclass__ attribute is no longer used, in favor of a keyword argument in the list of base classes.
The behavior of metaclasses however stays largely the same.
One thing added to metaclasses in Python 3 is that you can also pass attributes as keyword-arguments into a metaclass, like so:
class Foo(object, metaclass=something, kwarg1=value1, kwarg2=value2):
...
Read the section below for how Python handles this.
Custom metaclasses
The main purpose of a metaclass is to change the class automatically,
when it's created.
You usually do this for APIs, where you want to create classes matching the
current context.
Imagine a stupid example, where you decide that all classes in your module
should have their attributes written in uppercase. There are several ways to
do this, but one way is to set __metaclass__ at the module level.
This way, all classes of this module will be created using this metaclass,
and we just have to tell the metaclass to turn all attributes to uppercase.
Luckily, __metaclass__ can actually be any callable, it doesn't need to be a
formal class (I know, something with 'class' in its name doesn't need to be
a class, go figure... but it's helpful).
So we will start with a simple example, by using a function.
# the metaclass will automatically get passed the same argument
# that you usually pass to `type`
def upper_attr(future_class_name, future_class_parents, future_class_attrs):
"""
Return a class object, with the list of its attribute turned
into uppercase.
"""
# pick up any attribute that doesn't start with '__' and uppercase it
uppercase_attrs = {
attr if attr.startswith("__") else attr.upper(): v
for attr, v in future_class_attrs.items()
}
# let `type` do the class creation
return type(future_class_name, future_class_parents, uppercase_attrs)
__metaclass__ = upper_attr # this will affect all classes in the module
class Foo(): # global __metaclass__ won't work with "object" though
# but we can define __metaclass__ here instead to affect only this class
# and this will work with "object" children
bar = 'bip'
Let's check:
>>> hasattr(Foo, 'bar')
False
>>> hasattr(Foo, 'BAR')
True
>>> Foo.BAR
'bip'
Now, let's do exactly the same, but using a real class for a metaclass:
# remember that `type` is actually a class like `str` and `int`
# so you can inherit from it
class UpperAttrMetaclass(type):
# __new__ is the method called before __init__
# it's the method that creates the object and returns it
# while __init__ just initializes the object passed as parameter
# you rarely use __new__, except when you want to control how the object
# is created.
# here the created object is the class, and we want to customize it
# so we override __new__
# you can do some stuff in __init__ too if you wish
# some advanced use involves overriding __call__ as well, but we won't
# see this
def __new__(upperattr_metaclass, future_class_name,
future_class_parents, future_class_attrs):
uppercase_attrs = {
attr if attr.startswith("__") else attr.upper(): v
for attr, v in future_class_attrs.items()
}
return type(future_class_name, future_class_parents, uppercase_attrs)
Let's rewrite the above, but with shorter and more realistic variable names now that we know what they mean:
class UpperAttrMetaclass(type):
def __new__(cls, clsname, bases, attrs):
uppercase_attrs = {
attr if attr.startswith("__") else attr.upper(): v
for attr, v in attrs.items()
}
return type(clsname, bases, uppercase_attrs)
You may have noticed the extra argument cls. There is
nothing special about it: __new__ always receives the class it's defined in, as the first parameter. Just like you have self for ordinary methods which receive the instance as the first parameter, or the defining class for class methods.
But this is not proper OOP. We are calling type directly and we aren't overriding or calling the parent's __new__. Let's do that instead:
class UpperAttrMetaclass(type):
def __new__(cls, clsname, bases, attrs):
uppercase_attrs = {
attr if attr.startswith("__") else attr.upper(): v
for attr, v in attrs.items()
}
return type.__new__(cls, clsname, bases, uppercase_attrs)
We can make it even cleaner by using super, which will ease inheritance (because yes, you can have metaclasses, inheriting from metaclasses, inheriting from type):
class UpperAttrMetaclass(type):
def __new__(cls, clsname, bases, attrs):
uppercase_attrs = {
attr if attr.startswith("__") else attr.upper(): v
for attr, v in attrs.items()
}
# Python 2 requires passing arguments to super:
return super(UpperAttrMetaclass, cls).__new__(
cls, clsname, bases, uppercase_attrs)
# Python 3 can use no-arg super() which infers them:
return super().__new__(cls, clsname, bases, uppercase_attrs)
Oh, and in Python 3 if you do this call with keyword arguments, like this:
class Foo(object, metaclass=MyMetaclass, kwarg1=value1):
...
It translates to this in the metaclass to use it:
class MyMetaclass(type):
def __new__(cls, clsname, bases, dct, kwargs1=default):
...
That's it. There is really nothing more about metaclasses.
The reason behind the complexity of the code using metaclasses is not because
of metaclasses, it's because you usually use metaclasses to do twisted stuff
relying on introspection, manipulating inheritance, vars such as __dict__, etc.
Indeed, metaclasses are especially useful to do black magic, and therefore
complicated stuff. But by themselves, they are simple:
intercept a class creation
modify the class
return the modified class
Why would you use metaclasses classes instead of functions?
Since __metaclass__ can accept any callable, why would you use a class
since it's obviously more complicated?
There are several reasons to do so:
The intention is clear. When you read UpperAttrMetaclass(type), you know
what's going to follow
You can use OOP. Metaclass can inherit from metaclass, override parent methods. Metaclasses can even use metaclasses.
Subclasses of a class will be instances of its metaclass if you specified a metaclass-class, but not with a metaclass-function.
You can structure your code better. You never use metaclasses for something as trivial as the above example. It's usually for something complicated. Having the ability to make several methods and group them in one class is very useful to make the code easier to read.
You can hook on __new__, __init__ and __call__. Which will allow you to do different stuff, Even if usually you can do it all in __new__,
some people are just more comfortable using __init__.
These are called metaclasses, damn it! It must mean something!
Why would you use metaclasses?
Now the big question. Why would you use some obscure error-prone feature?
Well, usually you don't:
Metaclasses are deeper magic that
99% of users should never worry about it.
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).
Python Guru Tim Peters
The main use case for a metaclass is creating an API. A typical example of this is the Django ORM. It allows you to define something like this:
class Person(models.Model):
name = models.CharField(max_length=30)
age = models.IntegerField()
But if you do this:
person = Person(name='bob', age='35')
print(person.age)
It won't return an IntegerField object. It will return an int, and can even take it directly from the database.
This is possible because models.Model defines __metaclass__ and
it uses some magic that will turn the Person you just defined with simple statements
into a complex hook to a database field.
Django makes something complex look simple by exposing a simple API
and using metaclasses, recreating code from this API to do the real job
behind the scenes.
The last word
First, you know that classes are objects that can create instances.
Well, in fact, classes are themselves instances. Of metaclasses.
>>> class Foo(object): pass
>>> id(Foo)
142630324
Everything is an object in Python, and they are all either instance of classes
or instances of metaclasses.
Except for type.
type is actually its own metaclass. This is not something you could
reproduce in pure Python, and is done by cheating a little bit at the implementation
level.
Secondly, metaclasses are complicated. You may not want to use them for
very simple class alterations. You can change classes by using two different techniques:
monkey patching
class decorators
99% of the time you need class alteration, you are better off using these.
But 98% of the time, you don't need class alteration at all.
A metaclass is the class of a class. A class defines how an instance of the class (i.e. an object) behaves while a metaclass defines how a class behaves. A class is an instance of a metaclass.
While in Python you can use arbitrary callables for metaclasses (like Jerub shows), the better approach is to make it an actual class itself. type is the usual metaclass in Python. type is itself a class, and it is its own type. You won't be able to recreate something like type purely in Python, but Python cheats a little. To create your own metaclass in Python you really just want to subclass type.
A metaclass is most commonly used as a class-factory. When you create an object by calling the class, Python creates a new class (when it executes the 'class' statement) by calling the metaclass. Combined with the normal __init__ and __new__ methods, metaclasses therefore allow you to do 'extra things' when creating a class, like registering the new class with some registry or replace the class with something else entirely.
When the class statement is executed, Python first executes the body of the class statement as a normal block of code. The resulting namespace (a dict) holds the attributes of the class-to-be. The metaclass is determined by looking at the baseclasses of the class-to-be (metaclasses are inherited), at the __metaclass__ attribute of the class-to-be (if any) or the __metaclass__ global variable. The metaclass is then called with the name, bases and attributes of the class to instantiate it.
However, metaclasses actually define the type of a class, not just a factory for it, so you can do much more with them. You can, for instance, define normal methods on the metaclass. These metaclass-methods are like classmethods in that they can be called on the class without an instance, but they are also not like classmethods in that they cannot be called on an instance of the class. type.__subclasses__() is an example of a method on the type metaclass. You can also define the normal 'magic' methods, like __add__, __iter__ and __getattr__, to implement or change how the class behaves.
Here's an aggregated example of the bits and pieces:
def make_hook(f):
"""Decorator to turn 'foo' method into '__foo__'"""
f.is_hook = 1
return f
class MyType(type):
def __new__(mcls, name, bases, attrs):
if name.startswith('None'):
return None
# Go over attributes and see if they should be renamed.
newattrs = {}
for attrname, attrvalue in attrs.iteritems():
if getattr(attrvalue, 'is_hook', 0):
newattrs['__%s__' % attrname] = attrvalue
else:
newattrs[attrname] = attrvalue
return super(MyType, mcls).__new__(mcls, name, bases, newattrs)
def __init__(self, name, bases, attrs):
super(MyType, self).__init__(name, bases, attrs)
# classregistry.register(self, self.interfaces)
print "Would register class %s now." % self
def __add__(self, other):
class AutoClass(self, other):
pass
return AutoClass
# Alternatively, to autogenerate the classname as well as the class:
# return type(self.__name__ + other.__name__, (self, other), {})
def unregister(self):
# classregistry.unregister(self)
print "Would unregister class %s now." % self
class MyObject:
__metaclass__ = MyType
class NoneSample(MyObject):
pass
# Will print "NoneType None"
print type(NoneSample), repr(NoneSample)
class Example(MyObject):
def __init__(self, value):
self.value = value
#make_hook
def add(self, other):
return self.__class__(self.value + other.value)
# Will unregister the class
Example.unregister()
inst = Example(10)
# Will fail with an AttributeError
#inst.unregister()
print inst + inst
class Sibling(MyObject):
pass
ExampleSibling = Example + Sibling
# ExampleSibling is now a subclass of both Example and Sibling (with no
# content of its own) although it will believe it's called 'AutoClass'
print ExampleSibling
print ExampleSibling.__mro__
Note, this answer is for Python 2.x as it was written in 2008, metaclasses are slightly different in 3.x.
Metaclasses are the secret sauce that make 'class' work. The default metaclass for a new style object is called 'type'.
class type(object)
| type(object) -> the object's type
| type(name, bases, dict) -> a new type
Metaclasses take 3 args. 'name', 'bases' and 'dict'
Here is where the secret starts. Look for where name, bases and the dict come from in this example class definition.
class ThisIsTheName(Bases, Are, Here):
All_the_code_here
def doesIs(create, a):
dict
Lets define a metaclass that will demonstrate how 'class:' calls it.
def test_metaclass(name, bases, dict):
print 'The Class Name is', name
print 'The Class Bases are', bases
print 'The dict has', len(dict), 'elems, the keys are', dict.keys()
return "yellow"
class TestName(object, None, int, 1):
__metaclass__ = test_metaclass
foo = 1
def baz(self, arr):
pass
print 'TestName = ', repr(TestName)
# output =>
The Class Name is TestName
The Class Bases are (<type 'object'>, None, <type 'int'>, 1)
The dict has 4 elems, the keys are ['baz', '__module__', 'foo', '__metaclass__']
TestName = 'yellow'
And now, an example that actually means something, this will automatically make the variables in the list "attributes" set on the class, and set to None.
def init_attributes(name, bases, dict):
if 'attributes' in dict:
for attr in dict['attributes']:
dict[attr] = None
return type(name, bases, dict)
class Initialised(object):
__metaclass__ = init_attributes
attributes = ['foo', 'bar', 'baz']
print 'foo =>', Initialised.foo
# output=>
foo => None
Note that the magic behaviour that Initialised gains by having the metaclass init_attributes is not passed onto a subclass of Initialised.
Here is an even more concrete example, showing how you can subclass 'type' to make a metaclass that performs an action when the class is created. This is quite tricky:
class MetaSingleton(type):
instance = None
def __call__(cls, *args, **kw):
if cls.instance is None:
cls.instance = super(MetaSingleton, cls).__call__(*args, **kw)
return cls.instance
class Foo(object):
__metaclass__ = MetaSingleton
a = Foo()
b = Foo()
assert a is b
Others have explained how metaclasses work and how they fit into the Python type system. Here's an example of what they can be used for. In a testing framework I wrote, I wanted to keep track of the order in which classes were defined, so that I could later instantiate them in this order. I found it easiest to do this using a metaclass.
class MyMeta(type):
counter = 0
def __init__(cls, name, bases, dic):
type.__init__(cls, name, bases, dic)
cls._order = MyMeta.counter
MyMeta.counter += 1
class MyType(object): # Python 2
__metaclass__ = MyMeta
class MyType(metaclass=MyMeta): # Python 3
pass
Anything that's a subclass of MyType then gets a class attribute _order that records the order in which the classes were defined.
One use for metaclasses is adding new properties and methods to an instance automatically.
For example, if you look at Django models, their definition looks a bit confusing. It looks as if you are only defining class properties:
class Person(models.Model):
first_name = models.CharField(max_length=30)
last_name = models.CharField(max_length=30)
However, at runtime the Person objects are filled with all sorts of useful methods. See the source for some amazing metaclassery.
I think the ONLamp introduction to metaclass programming is well written and gives a really good introduction to the topic despite being several years old already.
http://www.onlamp.com/pub/a/python/2003/04/17/metaclasses.html (archived at https://web.archive.org/web/20080206005253/http://www.onlamp.com/pub/a/python/2003/04/17/metaclasses.html)
In short: A class is a blueprint for the creation of an instance, a metaclass is a blueprint for the creation of a class. It can be easily seen that in Python classes need to be first-class objects too to enable this behavior.
I've never written one myself, but I think one of the nicest uses of metaclasses can be seen in the Django framework. The model classes use a metaclass approach to enable a declarative style of writing new models or form classes. While the metaclass is creating the class, all members get the possibility to customize the class itself.
Creating a new model
The metaclass enabling this
The thing that's left to say is: If you don't know what metaclasses are, the probability that you will not need them is 99%.
What are metaclasses? What do you use them for?
TLDR: A metaclass instantiates and defines behavior for a class just like a class instantiates and defines behavior for an instance.
Pseudocode:
>>> Class(...)
instance
The above should look familiar. Well, where does Class come from? It's an instance of a metaclass (also pseudocode):
>>> Metaclass(...)
Class
In real code, we can pass the default metaclass, type, everything we need to instantiate a class and we get a class:
>>> type('Foo', (object,), {}) # requires a name, bases, and a namespace
<class '__main__.Foo'>
Putting it differently
A class is to an instance as a metaclass is to a class.
When we instantiate an object, we get an instance:
>>> object() # instantiation of class
<object object at 0x7f9069b4e0b0> # instance
Likewise, when we define a class explicitly with the default metaclass, type, we instantiate it:
>>> type('Object', (object,), {}) # instantiation of metaclass
<class '__main__.Object'> # instance
Put another way, a class is an instance of a metaclass:
>>> isinstance(object, type)
True
Put a third way, a metaclass is a class's class.
>>> type(object) == type
True
>>> object.__class__
<class 'type'>
When you write a class definition and Python executes it, it uses a metaclass to instantiate the class object (which will, in turn, be used to instantiate instances of that class).
Just as we can use class definitions to change how custom object instances behave, we can use a metaclass class definition to change the way a class object behaves.
What can they be used for? From the docs:
The potential uses for metaclasses are boundless. Some ideas that have been explored include logging, interface checking, automatic delegation, automatic property creation, proxies, frameworks, and automatic resource locking/synchronization.
Nevertheless, it is usually encouraged for users to avoid using metaclasses unless absolutely necessary.
You use a metaclass every time you create a class:
When you write a class definition, for example, like this,
class Foo(object):
'demo'
You instantiate a class object.
>>> Foo
<class '__main__.Foo'>
>>> isinstance(Foo, type), isinstance(Foo, object)
(True, True)
It is the same as functionally calling type with the appropriate arguments and assigning the result to a variable of that name:
name = 'Foo'
bases = (object,)
namespace = {'__doc__': 'demo'}
Foo = type(name, bases, namespace)
Note, some things automatically get added to the __dict__, i.e., the namespace:
>>> Foo.__dict__
dict_proxy({'__dict__': <attribute '__dict__' of 'Foo' objects>,
'__module__': '__main__', '__weakref__': <attribute '__weakref__'
of 'Foo' objects>, '__doc__': 'demo'})
The metaclass of the object we created, in both cases, is type.
(A side-note on the contents of the class __dict__: __module__ is there because classes must know where they are defined, and __dict__ and __weakref__ are there because we don't define __slots__ - if we define __slots__ we'll save a bit of space in the instances, as we can disallow __dict__ and __weakref__ by excluding them. For example:
>>> Baz = type('Bar', (object,), {'__doc__': 'demo', '__slots__': ()})
>>> Baz.__dict__
mappingproxy({'__doc__': 'demo', '__slots__': (), '__module__': '__main__'})
... but I digress.)
We can extend type just like any other class definition:
Here's the default __repr__ of classes:
>>> Foo
<class '__main__.Foo'>
One of the most valuable things we can do by default in writing a Python object is to provide it with a good __repr__. When we call help(repr) we learn that there's a good test for a __repr__ that also requires a test for equality - obj == eval(repr(obj)). The following simple implementation of __repr__ and __eq__ for class instances of our type class provides us with a demonstration that may improve on the default __repr__ of classes:
class Type(type):
def __repr__(cls):
"""
>>> Baz
Type('Baz', (Foo, Bar,), {'__module__': '__main__', '__doc__': None})
>>> eval(repr(Baz))
Type('Baz', (Foo, Bar,), {'__module__': '__main__', '__doc__': None})
"""
metaname = type(cls).__name__
name = cls.__name__
parents = ', '.join(b.__name__ for b in cls.__bases__)
if parents:
parents += ','
namespace = ', '.join(': '.join(
(repr(k), repr(v) if not isinstance(v, type) else v.__name__))
for k, v in cls.__dict__.items())
return '{0}(\'{1}\', ({2}), {{{3}}})'.format(metaname, name, parents, namespace)
def __eq__(cls, other):
"""
>>> Baz == eval(repr(Baz))
True
"""
return (cls.__name__, cls.__bases__, cls.__dict__) == (
other.__name__, other.__bases__, other.__dict__)
So now when we create an object with this metaclass, the __repr__ echoed on the command line provides a much less ugly sight than the default:
>>> class Bar(object): pass
>>> Baz = Type('Baz', (Foo, Bar,), {'__module__': '__main__', '__doc__': None})
>>> Baz
Type('Baz', (Foo, Bar,), {'__module__': '__main__', '__doc__': None})
With a nice __repr__ defined for the class instance, we have a stronger ability to debug our code. However, much further checking with eval(repr(Class)) is unlikely (as functions would be rather impossible to eval from their default __repr__'s).
An expected usage: __prepare__ a namespace
If, for example, we want to know in what order a class's methods are created in, we could provide an ordered dict as the namespace of the class. We would do this with __prepare__ which returns the namespace dict for the class if it is implemented in Python 3:
from collections import OrderedDict
class OrderedType(Type):
#classmethod
def __prepare__(metacls, name, bases, **kwargs):
return OrderedDict()
def __new__(cls, name, bases, namespace, **kwargs):
result = Type.__new__(cls, name, bases, dict(namespace))
result.members = tuple(namespace)
return result
And usage:
class OrderedMethodsObject(object, metaclass=OrderedType):
def method1(self): pass
def method2(self): pass
def method3(self): pass
def method4(self): pass
And now we have a record of the order in which these methods (and other class attributes) were created:
>>> OrderedMethodsObject.members
('__module__', '__qualname__', 'method1', 'method2', 'method3', 'method4')
Note, this example was adapted from the documentation - the new enum in the standard library does this.
So what we did was instantiate a metaclass by creating a class. We can also treat the metaclass as we would any other class. It has a method resolution order:
>>> inspect.getmro(OrderedType)
(<class '__main__.OrderedType'>, <class '__main__.Type'>, <class 'type'>, <class 'object'>)
And it has approximately the correct repr (which we can no longer eval unless we can find a way to represent our functions.):
>>> OrderedMethodsObject
OrderedType('OrderedMethodsObject', (object,), {'method1': <function OrderedMethodsObject.method1 at 0x0000000002DB01E0>, 'members': ('__module__', '__qualname__', 'method1', 'method2', 'method3', 'method4'), 'method3': <function OrderedMet
hodsObject.method3 at 0x0000000002DB02F0>, 'method2': <function OrderedMethodsObject.method2 at 0x0000000002DB0268>, '__module__': '__main__', '__weakref__': <attribute '__weakref__' of 'OrderedMethodsObject' objects>, '__doc__': None, '__d
ict__': <attribute '__dict__' of 'OrderedMethodsObject' objects>, 'method4': <function OrderedMethodsObject.method4 at 0x0000000002DB0378>})
Python 3 update
There are (at this point) two key methods in a metaclass:
__prepare__, and
__new__
__prepare__ lets you supply a custom mapping (such as an OrderedDict) to be used as the namespace while the class is being created. You must return an instance of whatever namespace you choose. If you don't implement __prepare__ a normal dict is used.
__new__ is responsible for the actual creation/modification of the final class.
A bare-bones, do-nothing-extra metaclass would like:
class Meta(type):
def __prepare__(metaclass, cls, bases):
return dict()
def __new__(metacls, cls, bases, clsdict):
return super().__new__(metacls, cls, bases, clsdict)
A simple example:
Say you want some simple validation code to run on your attributes -- like it must always be an int or a str. Without a metaclass, your class would look something like:
class Person:
weight = ValidateType('weight', int)
age = ValidateType('age', int)
name = ValidateType('name', str)
As you can see, you have to repeat the name of the attribute twice. This makes typos possible along with irritating bugs.
A simple metaclass can address that problem:
class Person(metaclass=Validator):
weight = ValidateType(int)
age = ValidateType(int)
name = ValidateType(str)
This is what the metaclass would look like (not using __prepare__ since it is not needed):
class Validator(type):
def __new__(metacls, cls, bases, clsdict):
# search clsdict looking for ValidateType descriptors
for name, attr in clsdict.items():
if isinstance(attr, ValidateType):
attr.name = name
attr.attr = '_' + name
# create final class and return it
return super().__new__(metacls, cls, bases, clsdict)
A sample run of:
p = Person()
p.weight = 9
print(p.weight)
p.weight = '9'
produces:
9
Traceback (most recent call last):
File "simple_meta.py", line 36, in <module>
p.weight = '9'
File "simple_meta.py", line 24, in __set__
(self.name, self.type, value))
TypeError: weight must be of type(s) <class 'int'> (got '9')
Note: This example is simple enough it could have also been accomplished with a class decorator, but presumably an actual metaclass would be doing much more.
The 'ValidateType' class for reference:
class ValidateType:
def __init__(self, type):
self.name = None # will be set by metaclass
self.attr = None # will be set by metaclass
self.type = type
def __get__(self, inst, cls):
if inst is None:
return self
else:
return inst.__dict__[self.attr]
def __set__(self, inst, value):
if not isinstance(value, self.type):
raise TypeError('%s must be of type(s) %s (got %r)' %
(self.name, self.type, value))
else:
inst.__dict__[self.attr] = value
Role of a metaclass' __call__() method when creating a class instance
If you've done Python programming for more than a few months you'll eventually stumble upon code that looks like this:
# define a class
class SomeClass(object):
# ...
# some definition here ...
# ...
# create an instance of it
instance = SomeClass()
# then call the object as if it's a function
result = instance('foo', 'bar')
The latter is possible when you implement the __call__() magic method on the class.
class SomeClass(object):
# ...
# some definition here ...
# ...
def __call__(self, foo, bar):
return bar + foo
The __call__() method is invoked when an instance of a class is used as a callable. But as we've seen from previous answers a class itself is an instance of a metaclass, so when we use the class as a callable (i.e. when we create an instance of it) we're actually calling its metaclass' __call__() method. At this point most Python programmers are a bit confused because they've been told that when creating an instance like this instance = SomeClass() you're calling its __init__() method. Some who've dug a bit deeper know that before __init__() there's __new__(). Well, today another layer of truth is being revealed, before __new__() there's the metaclass' __call__().
Let's study the method call chain from specifically the perspective of creating an instance of a class.
This is a metaclass that logs exactly the moment before an instance is created and the moment it's about to return it.
class Meta_1(type):
def __call__(cls):
print "Meta_1.__call__() before creating an instance of ", cls
instance = super(Meta_1, cls).__call__()
print "Meta_1.__call__() about to return instance."
return instance
This is a class that uses that metaclass
class Class_1(object):
__metaclass__ = Meta_1
def __new__(cls):
print "Class_1.__new__() before creating an instance."
instance = super(Class_1, cls).__new__(cls)
print "Class_1.__new__() about to return instance."
return instance
def __init__(self):
print "entering Class_1.__init__() for instance initialization."
super(Class_1,self).__init__()
print "exiting Class_1.__init__()."
And now let's create an instance of Class_1
instance = Class_1()
# Meta_1.__call__() before creating an instance of <class '__main__.Class_1'>.
# Class_1.__new__() before creating an instance.
# Class_1.__new__() about to return instance.
# entering Class_1.__init__() for instance initialization.
# exiting Class_1.__init__().
# Meta_1.__call__() about to return instance.
Observe that the code above doesn't actually do anything more than logging the tasks. Each method delegates the actual work to its parent's implementation, thus keeping the default behavior. Since type is Meta_1's parent class (type being the default parent metaclass) and considering the ordering sequence of the output above, we now have a clue as to what would be the pseudo implementation of type.__call__():
class type:
def __call__(cls, *args, **kwarg):
# ... maybe a few things done to cls here
# then we call __new__() on the class to create an instance
instance = cls.__new__(cls, *args, **kwargs)
# ... maybe a few things done to the instance here
# then we initialize the instance with its __init__() method
instance.__init__(*args, **kwargs)
# ... maybe a few more things done to instance here
# then we return it
return instance
We can see that the metaclass' __call__() method is the one that's called first. It then delegates creation of the instance to the class's __new__() method and initialization to the instance's __init__(). It's also the one that ultimately returns the instance.
From the above it stems that the metaclass' __call__() is also given the opportunity to decide whether or not a call to Class_1.__new__() or Class_1.__init__() will eventually be made. Over the course of its execution it could actually return an object that hasn't been touched by either of these methods. Take for example this approach to the singleton pattern:
class Meta_2(type):
singletons = {}
def __call__(cls, *args, **kwargs):
if cls in Meta_2.singletons:
# we return the only instance and skip a call to __new__()
# and __init__()
print ("{} singleton returning from Meta_2.__call__(), "
"skipping creation of new instance.".format(cls))
return Meta_2.singletons[cls]
# else if the singleton isn't present we proceed as usual
print "Meta_2.__call__() before creating an instance."
instance = super(Meta_2, cls).__call__(*args, **kwargs)
Meta_2.singletons[cls] = instance
print "Meta_2.__call__() returning new instance."
return instance
class Class_2(object):
__metaclass__ = Meta_2
def __new__(cls, *args, **kwargs):
print "Class_2.__new__() before creating instance."
instance = super(Class_2, cls).__new__(cls)
print "Class_2.__new__() returning instance."
return instance
def __init__(self, *args, **kwargs):
print "entering Class_2.__init__() for initialization."
super(Class_2, self).__init__()
print "exiting Class_2.__init__()."
Let's observe what happens when repeatedly trying to create an object of type Class_2
a = Class_2()
# Meta_2.__call__() before creating an instance.
# Class_2.__new__() before creating instance.
# Class_2.__new__() returning instance.
# entering Class_2.__init__() for initialization.
# exiting Class_2.__init__().
# Meta_2.__call__() returning new instance.
b = Class_2()
# <class '__main__.Class_2'> singleton returning from Meta_2.__call__(), skipping creation of new instance.
c = Class_2()
# <class '__main__.Class_2'> singleton returning from Meta_2.__call__(), skipping creation of new instance.
a is b is c # True
A metaclass is a class that tells how (some) other class should be created.
This is a case where I saw metaclass as a solution to my problem:
I had a really complicated problem, that probably could have been solved differently, but I chose to solve it using a metaclass. Because of the complexity, it is one of the few modules I have written where the comments in the module surpass the amount of code that has been written. Here it is...
#!/usr/bin/env python
# Copyright (C) 2013-2014 Craig Phillips. All rights reserved.
# This requires some explaining. The point of this metaclass excercise is to
# create a static abstract class that is in one way or another, dormant until
# queried. I experimented with creating a singlton on import, but that did
# not quite behave how I wanted it to. See now here, we are creating a class
# called GsyncOptions, that on import, will do nothing except state that its
# class creator is GsyncOptionsType. This means, docopt doesn't parse any
# of the help document, nor does it start processing command line options.
# So importing this module becomes really efficient. The complicated bit
# comes from requiring the GsyncOptions class to be static. By that, I mean
# any property on it, may or may not exist, since they are not statically
# defined; so I can't simply just define the class with a whole bunch of
# properties that are #property #staticmethods.
#
# So here's how it works:
#
# Executing 'from libgsync.options import GsyncOptions' does nothing more
# than load up this module, define the Type and the Class and import them
# into the callers namespace. Simple.
#
# Invoking 'GsyncOptions.debug' for the first time, or any other property
# causes the __metaclass__ __getattr__ method to be called, since the class
# is not instantiated as a class instance yet. The __getattr__ method on
# the type then initialises the class (GsyncOptions) via the __initialiseClass
# method. This is the first and only time the class will actually have its
# dictionary statically populated. The docopt module is invoked to parse the
# usage document and generate command line options from it. These are then
# paired with their defaults and what's in sys.argv. After all that, we
# setup some dynamic properties that could not be defined by their name in
# the usage, before everything is then transplanted onto the actual class
# object (or static class GsyncOptions).
#
# Another piece of magic, is to allow command line options to be set in
# in their native form and be translated into argparse style properties.
#
# Finally, the GsyncListOptions class is actually where the options are
# stored. This only acts as a mechanism for storing options as lists, to
# allow aggregation of duplicate options or options that can be specified
# multiple times. The __getattr__ call hides this by default, returning the
# last item in a property's list. However, if the entire list is required,
# calling the 'list()' method on the GsyncOptions class, returns a reference
# to the GsyncListOptions class, which contains all of the same properties
# but as lists and without the duplication of having them as both lists and
# static singlton values.
#
# So this actually means that GsyncOptions is actually a static proxy class...
#
# ...And all this is neatly hidden within a closure for safe keeping.
def GetGsyncOptionsType():
class GsyncListOptions(object):
__initialised = False
class GsyncOptionsType(type):
def __initialiseClass(cls):
if GsyncListOptions._GsyncListOptions__initialised: return
from docopt import docopt
from libgsync.options import doc
from libgsync import __version__
options = docopt(
doc.__doc__ % __version__,
version = __version__,
options_first = True
)
paths = options.pop('<path>', None)
setattr(cls, "destination_path", paths.pop() if paths else None)
setattr(cls, "source_paths", paths)
setattr(cls, "options", options)
for k, v in options.iteritems():
setattr(cls, k, v)
GsyncListOptions._GsyncListOptions__initialised = True
def list(cls):
return GsyncListOptions
def __getattr__(cls, name):
cls.__initialiseClass()
return getattr(GsyncListOptions, name)[-1]
def __setattr__(cls, name, value):
# Substitut option names: --an-option-name for an_option_name
import re
name = re.sub(r'^__', "", re.sub(r'-', "_", name))
listvalue = []
# Ensure value is converted to a list type for GsyncListOptions
if isinstance(value, list):
if value:
listvalue = [] + value
else:
listvalue = [ None ]
else:
listvalue = [ value ]
type.__setattr__(GsyncListOptions, name, listvalue)
# Cleanup this module to prevent tinkering.
import sys
module = sys.modules[__name__]
del module.__dict__['GetGsyncOptionsType']
return GsyncOptionsType
# Our singlton abstract proxy class.
class GsyncOptions(object):
__metaclass__ = GetGsyncOptionsType()
The tl;dr version
The type(obj) function gets you the type of an object.
The type() of a class is its metaclass.
To use a metaclass:
class Foo(object):
__metaclass__ = MyMetaClass
type is its own metaclass. The class of a class is a metaclass-- the body of a class is the arguments passed to the metaclass that is used to construct the class.
Here you can read about how to use metaclasses to customize class construction.
type is actually a metaclass -- a class that creates another classes.
Most metaclass are the subclasses of type. The metaclass receives the new class as its first argument and provide access to class object with details as mentioned below:
>>> class MetaClass(type):
... def __init__(cls, name, bases, attrs):
... print ('class name: %s' %name )
... print ('Defining class %s' %cls)
... print('Bases %s: ' %bases)
... print('Attributes')
... for (name, value) in attrs.items():
... print ('%s :%r' %(name, value))
...
>>> class NewClass(object, metaclass=MetaClass):
... get_choch='dairy'
...
class name: NewClass
Bases <class 'object'>:
Defining class <class 'NewClass'>
get_choch :'dairy'
__module__ :'builtins'
__qualname__ :'NewClass'
Note:
Notice that the class was not instantiated at any time; the simple act of creating the class triggered execution of the metaclass.
Python classes are themselves objects - as in instance - of their meta-class.
The default metaclass, which is applied when when you determine classes as:
class foo:
...
meta class are used to apply some rule to an entire set of classes. For example, suppose you're building an ORM to access a database, and you want records from each table to be of a class mapped to that table (based on fields, business rules, etc..,), a possible use of metaclass is for instance, connection pool logic, which is share by all classes of record from all tables. Another use is logic to to support foreign keys, which involves multiple classes of records.
when you define metaclass, you subclass type, and can overrided the following magic methods to insert your logic.
class somemeta(type):
__new__(mcs, name, bases, clsdict):
"""
mcs: is the base metaclass, in this case type.
name: name of the new class, as provided by the user.
bases: tuple of base classes
clsdict: a dictionary containing all methods and attributes defined on class
you must return a class object by invoking the __new__ constructor on the base metaclass.
ie:
return type.__call__(mcs, name, bases, clsdict).
in the following case:
class foo(baseclass):
__metaclass__ = somemeta
an_attr = 12
def bar(self):
...
#classmethod
def foo(cls):
...
arguments would be : ( somemeta, "foo", (baseclass, baseofbase,..., object), {"an_attr":12, "bar": <function>, "foo": <bound class method>}
you can modify any of these values before passing on to type
"""
return type.__call__(mcs, name, bases, clsdict)
def __init__(self, name, bases, clsdict):
"""
called after type has been created. unlike in standard classes, __init__ method cannot modify the instance (cls) - and should be used for class validaton.
"""
pass
def __prepare__():
"""
returns a dict or something that can be used as a namespace.
the type will then attach methods and attributes from class definition to it.
call order :
somemeta.__new__ -> type.__new__ -> type.__init__ -> somemeta.__init__
"""
return dict()
def mymethod(cls):
""" works like a classmethod, but for class objects. Also, my method will not be visible to instances of cls.
"""
pass
anyhow, those two are the most commonly used hooks. metaclassing is powerful, and above is nowhere near and exhaustive list of uses for metaclassing.
The type() function can return the type of an object or create a new type,
for example, we can create a Hi class with the type() function and do not need to use this way with class Hi(object):
def func(self, name='mike'):
print('Hi, %s.' % name)
Hi = type('Hi', (object,), dict(hi=func))
h = Hi()
h.hi()
Hi, mike.
type(Hi)
type
type(h)
__main__.Hi
In addition to using type() to create classes dynamically, you can control creation behavior of class and use metaclass.
According to the Python object model, the class is the object, so the class must be an instance of another certain class.
By default, a Python class is instance of the type class. That is, type is metaclass of most of the built-in classes and metaclass of user-defined classes.
class ListMetaclass(type):
def __new__(cls, name, bases, attrs):
attrs['add'] = lambda self, value: self.append(value)
return type.__new__(cls, name, bases, attrs)
class CustomList(list, metaclass=ListMetaclass):
pass
lst = CustomList()
lst.add('custom_list_1')
lst.add('custom_list_2')
lst
['custom_list_1', 'custom_list_2']
Magic will take effect when we passed keyword arguments in metaclass, it indicates the Python interpreter to create the CustomList through ListMetaclass. new (), at this point, we can modify the class definition, for example, and add a new method and then return the revised definition.
In addition to the published answers I can say that a metaclass defines the behaviour for a class. So, you can explicitly set your metaclass. Whenever Python gets a keyword class then it starts searching for the metaclass. If it's not found – the default metaclass type is used to create the class's object. Using the __metaclass__ attribute, you can set metaclass of your class:
class MyClass:
__metaclass__ = type
# write here other method
# write here one more method
print(MyClass.__metaclass__)
It'll produce the output like this:
class 'type'
And, of course, you can create your own metaclass to define the behaviour of any class that are created using your class.
For doing that, your default metaclass type class must be inherited as this is the main metaclass:
class MyMetaClass(type):
__metaclass__ = type
# you can write here any behaviour you want
class MyTestClass:
__metaclass__ = MyMetaClass
Obj = MyTestClass()
print(Obj.__metaclass__)
print(MyMetaClass.__metaclass__)
The output will be:
class '__main__.MyMetaClass'
class 'type'
Note that in python 3.6 a new dunder method __init_subclass__(cls, **kwargs) was introduced to replace a lot of common use cases for metaclasses. Is is called when a subclass of the defining class is created. See python docs.
Here's another example of what it can be used for:
You can use the metaclass to change the function of its instance (the class).
class MetaMemberControl(type):
__slots__ = ()
#classmethod
def __prepare__(mcs, f_cls_name, f_cls_parents, # f_cls means: future class
meta_args=None, meta_options=None): # meta_args and meta_options is not necessarily needed, just so you know.
f_cls_attr = dict()
if not "do something or if you want to define your cool stuff of dict...":
return dict(make_your_special_dict=None)
else:
return f_cls_attr
def __new__(mcs, f_cls_name, f_cls_parents, f_cls_attr,
meta_args=None, meta_options=None):
original_getattr = f_cls_attr.get('__getattribute__')
original_setattr = f_cls_attr.get('__setattr__')
def init_getattr(self, item):
if not item.startswith('_'): # you can set break points at here
alias_name = '_' + item
if alias_name in f_cls_attr['__slots__']:
item = alias_name
if original_getattr is not None:
return original_getattr(self, item)
else:
return super(eval(f_cls_name), self).__getattribute__(item)
def init_setattr(self, key, value):
if not key.startswith('_') and ('_' + key) in f_cls_attr['__slots__']:
raise AttributeError(f"you can't modify private members:_{key}")
if original_setattr is not None:
original_setattr(self, key, value)
else:
super(eval(f_cls_name), self).__setattr__(key, value)
f_cls_attr['__getattribute__'] = init_getattr
f_cls_attr['__setattr__'] = init_setattr
cls = super().__new__(mcs, f_cls_name, f_cls_parents, f_cls_attr)
return cls
class Human(metaclass=MetaMemberControl):
__slots__ = ('_age', '_name')
def __init__(self, name, age):
self._name = name
self._age = age
def __getattribute__(self, item):
"""
is just for IDE recognize.
"""
return super().__getattribute__(item)
""" with MetaMemberControl then you don't have to write as following
#property
def name(self):
return self._name
#property
def age(self):
return self._age
"""
def test_demo():
human = Human('Carson', 27)
# human.age = 18 # you can't modify private members:_age <-- this is defined by yourself.
# human.k = 18 # 'Human' object has no attribute 'k' <-- system error.
age1 = human._age # It's OK, although the IDE will show some warnings. (Access to a protected member _age of a class)
age2 = human.age # It's OK! see below:
"""
if you do not define `__getattribute__` at the class of Human,
the IDE will show you: Unresolved attribute reference 'age' for class 'Human'
but it's ok on running since the MetaMemberControl will help you.
"""
if __name__ == '__main__':
test_demo()
The metaclass is powerful, there are many things (such as monkey magic) you can do with it, but be careful this may only be known to you.
The top answer is correct.
But readers may be coming here searching answers about similarly named inner classes. They are present in popular libraries, such as Django and WTForms.
As DavidW points out in the comments beneath this answer, these are library-specific features and are not to be confused with the advanced, unrelated Python language feature with a similar name.
Rather, these are namespaces within classes' dicts. They are constructed using inner classes for sake of readability.
In this example special field, abstract is visibly separate from fields of Author model.
from django.db import models
class Author(models.Model):
name = models.CharField(max_length=50)
email = models.EmailField()
class Meta:
abstract = True
Another example is from the documentation for WTForms:
from wtforms.form import Form
from wtforms.csrf.session import SessionCSRF
from wtforms.fields import StringField
class MyBaseForm(Form):
class Meta:
csrf = True
csrf_class = SessionCSRF
name = StringField("name")
This syntax does not get special treatment in the python programming language. Meta is not a keyword here, and does not trigger metaclass behavior. Rather, third-party library code in packages like Django and WTForms reads this property in the constructors of certain classes, and elsewhere.
The presence of these declarations modifies the behavior of the classes that have these declarations. For example, WTForms reads self.Meta.csrf to determine if the form needs a csrf field.
In object-oriented programming, a metaclass is a class whose instances are classes. Just as an ordinary class defines the behavior of certain objects, a metaclass defines the behavior of certain class and their instances
The term metaclass simply means something used to create classes. In other words, it is the class of a class. The metaclass is used to create the class so like the object being an instance of a class, a class is an instance of a metaclass. In python classes are also considered objects.
A class, in Python, is an object, and just like any other object, it is an instance of "something". This "something" is what is termed as a Metaclass. This metaclass is a special type of class that creates other class's objects. Hence, metaclass is responsible for making new classes. This allows the programmer to customize the way classes are generated.
To create a metaclass, overriding of new() and init() methods is usually done. new() can be overridden to change the way objects are created, while init() can be overridden to change the way of initializing the object. Metaclass can be created by a number of ways. One of the ways is to use type() function. type() function, when called with 3 parameters, creates a metaclass. The parameters are :-
Class Name
Tuple having base classes inherited by class
A dictionary having all class methods and class variables
Another way of creating a metaclass comprises of 'metaclass' keyword. Define the metaclass as a simple class. In the parameters of inherited class, pass metaclass=metaclass_name
Metaclass can be specifically used in the following situations :-
when a particular effect has to be applied to all the subclasses
Automatic change of class (on creation) is required
By API developers
I saw an interesting use case for metaclasses in a package called classutilities. It checks if all class variables are in upper case format (it is convenient to have unified logic for configuration classes), and checks if there are no instance level methods in class.
Another interesting example for metaclases was deactivation of unittests based on complex conditions (checking values of multiple environmental variables).
In Python, a metaclass is a subclass of a subclass that determines how a subclass behaves. A class is an instance of another metaclass. In Python, a class specifies how the class's instance will behave.
Since metaclasses are in charge of class generation, you can write your own custom metaclasses to change how classes are created by performing additional actions or injecting code. Custom metaclasses aren't always important, but they can be.
look this:
Python 3.10.0rc2 (tags/v3.10.0rc2:839d789, Sep 7 2021, 18:51:45) [MSC v.1929 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> class Object:
... pass
...
>>> class Meta(type):
... test = 'Worked!!!'
... def __repr__(self):
... return 'This is "Meta" metaclass'
...
>>> class ObjectWithMetaClass(metaclass=Meta):
... pass
...
>>> Object or type(Object())
<class '__main__.Object'>
>>> ObjectWithMetaClass or type(ObjectWithMetaClass())
This is "Meta" metaclass
>>> Object.test
AttributeError: ...
>>> ObjectWithMetaClass.test
'Worked!!!'
>>> type(Object)
<class 'type'>
>>> type(ObjectWithMetaClass)
<class '__main__.Meta'>
>>> type(type(ObjectWithMetaClass))
<class 'type'>
>>> Object.__bases__
(<class 'object'>,)
>>> ObjectWithMetaClass.__bases__
(<class 'object'>,)
>>> type(ObjectWithMetaClass).__bases__
(<class 'type'>,)
>>> Object.__mro__
(<class '__main__.Object'>, <class 'object'>)
>>> ObjectWithMetaClass.__mro__
(This is "Meta" metaclass, <class 'object'>)
>>>
In other words, when an object was not created (type of object), we looking MetaClass.
i want to add a little on why type.__new__() over type()
first, take a look at these classes
In [1]: class MyMeta(type):
...: def __new__(cls, cls_name, bases, attrs):
...: print(cls, cls_name, bases, attrs)
...: return super().__new__(cls, cls_name, bases, attrs)
...:
In [2]: class AClass(metaclass=MyMeta):
...: pass
...:
<class '__main__.MyMeta'> AClass () {'__module__': '__main__', '__qualname__': 'AClass'}
In [3]: class BClass:
...: pass
...:
In [4]: AClass.__class__
Out[4]: __main__.MyMeta
In [5]: BClass.__class__
Out[5]: type
In [6]: class SubAClass(AClass):
...: pass
...:
<class '__main__.MyMeta'> SubAClass (<class '__main__.AClass'>,) {'__module__': '__main__', '__qualname__': 'SubAClass'}
when we were trying to create SubAClass a subclass of AClass, Python would take a look at the metaclass we designated to be used to create SubAClass
and in this case, we did not pass a metaclass for SubAClass, so Python got a None for metaclass.
and Python would try to pick up the first base class of SubAClass, which is AClass, has a metaclass, which is MyMeta, then it would call MyMeta.__new__ to create SubAClass
for simplicity, we can say
type.__new__ just assigned our metaclass to the parent.__class__(AClass.__class__).
and when a subclass was defined(SubAClass) by class statement, Python
would just use the parent.__class__ to create that subclass unless
we've manually passed a metaclass to our subclass
apparently, if you called type() instead of type.__new__, the class
would have type as its __class__ attr.
that means AClass would be equivalent of BClass, both of them have type
as their __class__ attr
how the searching of metaclass works in C code?
it works pretty much like what we've just mentioned
the function builtin___build_class__ would be called when you defined a class
and code is just so straightforward
static PyObject *
builtin___build_class__(PyObject *self, PyObject *const *args, Py_ssize_t nargs,
PyObject *kwnames){
if (meta == NULL) {
/* if there are no bases, use type: */
if (PyTuple_GET_SIZE(bases) == 0) {
meta = (PyObject *) (&PyType_Type);
}
/* else get the type of the first base */
else {
PyObject *base0 = PyTuple_GET_ITEM(bases, 0);
meta = (PyObject *)Py_TYPE(base0);
}
Py_INCREF(meta);
isclass = 1; /* meta is really a class */
}
PyObject *margs[3] = {name, bases, ns};
cls = PyObject_VectorcallDict(meta, margs, 3, mkw);
}
basically, meta = (PyObject *)Py_TYPE(base0); is everything we want to know
it can be translated to be
meta = MyMeta = AClass.__class__ = Py_TYPE(AClass)
In Python or in any other language we have a type for every variable or object we declare. For getting type of anything(variable,object,etc.) in Python we can use type() function.
Bypassing the metaclass keyword in the class definition we can customize the class creation process.
class meta(type):
pass
class baseclass(metaclass=meta): # This is Mestaclass
pass
class derivedclass(baseclass):
pass
print(type(meta))
print(type(baseclass))
print(type(derivedclass))
When defining a new class if no metaclass is defined the default type metaclass is used. If a given metaclass is not the object(instance) of type(), in that situation it is used directly as a metaclass.

Categories