When type
is called with three arguments it behaves as the (meta)class it is, and creates a new instance, ie. it produces a new class/type.
Dummy = type('OtherDummy', (), dict(x=1))
Dummy.__class__ # <type 'type'>
Dummy().__class__.__class__ # <type 'type'>
It is possible to subclass type
to create an custom metaclass.
class mytype(type):
def __init__(cls, name, bases, dict):
# call the base initializer
type.__init__(cls, name, bases, dict)
# perform custom initialization...
cls.__custom_attribute__ = 2
Now, we have a new custom mytype
metaclass which can be used to create classes in the same manner as type
.
MyDummy = mytype('MyDummy', (), dict(x=2))
MyDummy.__class__ # <class '__main__.mytype'>
MyDummy().__class__.__class__ # <class '__main__.mytype'>
MyDummy.__custom_attribute__ # 2
When we create a new class using the class
keyword the metaclass is by default chosen based on upon the baseclasses.
>>> class Foo(object):
... pass
>>> type(Foo)
type
In the above example the only baseclass is object
so our metaclass will be the type of object
, which is type
. It is possible override the default, however it depends on whether we use Python 2 or Python 3:
A special class-level attribute __metaclass__
can be used to specify the metaclass.
class MyDummy(object):
__metaclass__ = mytype
type(MyDummy) # <class '__main__.mytype'>
A special metaclass
keyword argument specify the metaclass.
class MyDummy(metaclass=mytype):
pass
type(MyDummy) # <class '__main__.mytype'>
Any keyword arguments (except metaclass
) in the class declaration will be passed to the metaclass. Thus class MyDummy(metaclass=mytype, x=2)
will pass x=2
as a keyword argument to the mytype
constructor.
Read this in-depth description of python meta-classes for more details.