I was writing a metaclass and accidentally did it like this:
class MetaCls(type):
def __new__(cls, name, bases, dict):
return type(name, bases, dict)
...instead of like this:
class MetaCls(type):
def __new__(cls, name, bases, dict):
return type.__new__(cls, name, bases, dict)
What exactly is the difference between these two metaclasses? And more specifically, what caused the first one to not work properly (some classes weren't called into by the metaclass)?
In the first example you're creating a whole new class:
while in the second case you're calling parent's
__new__
:Another way to achieve the same result:
MyMeta
is a callable so Python will use the special method__call__
.Python will look for
__call__
in theMyMeta
's type (which istype
in our case)MyClass = MyMeta(...)
is interpreted as:Inside the
type.__call__()
I imagine something like this:MyMeta.__new__()
will decide how theMyClass
is built:type.__new__(meta, cls, bases, attributes)
will set the correct metaclass (which isMyMeta
) forMyClass
type(cls, bases, attributes)
will set the default metaclass (which is type) forMyClass
What you get back from this is a new
type
, and not aMetaCls
instance at all. Consequently, your methods defined inMetaCls
(including__init__
) can't ever be called.type.__new__
will be called as part of creating that new type, yes, but the value ofcls
going into that function is going to betype
and notMetaCls
.Please refer to the annotation below, hope this helpful.
The first thing you need to figure out is how
object.__new__()
works.Here it is from the documentation:
So in mg.'s answer, the former doesn't call function
__init__
while the latter calls function__init__
after calling__new__
.It's all described pretty well here.
If you don't return the right type of object, there's no point to defining a custom metaclass.