Hello I am recently looking about the metaclass
in Python.
I learned about we can attach a metaclass to a class in this way:
class Metaclass(type):
...
class MyClass(metaclass=Metaclass):
...
- The first question
I wonder what's the principle of the keyword argument (metaclass=...
) in the above example. There seems no description for that in the doc
I know that there is keyword argument for a function, but I've never seen the form occurred in class inheritance.
- The second question
We know that we can create a class using type()
function in this way
cls = type(class_name, (base_class,), {func_name: func_ref})
Considering the metaclass=...
form, how can I pass metaclass when creating class using type()
instead of class
keyword?
Thanks stackoverflowers!
CodePudding user response:
In general, the keyword arguments used with a class
statement are passed to __init_subclass__
, to be used however that function sees fit. metaclass
, however, is used by the code generator itself to determine what gets called in order to define the class.
The metaclass is not an argument to be passed to a call to type
; it is the callable that gets called instead of type
. Very roughly speaking,
class MyClass(metaclass=Metaclass):
...
is turned into
MyClass = Metaclass('MyClass', (), ...)
type
is simply the default metaclass.
(The gory details of how a class
statement is executed can be found in Section 3.3.3 of the language documentation.)
Note that a metaclass does not have to be a subclass of type
. You can do truly horrific things with metaclasses, like
>>> class A(metaclass=lambda x, y, z: 3): pass
...
>>> type(A)
<class 'int'>
>>> A
3
It doesn't really matter what the metaclass returns, as long as it accepts 3 arguments.
Please don't write actual code like this, though. A class
statement should produce something that at least resembles a type.
In some sense, class
statements are less magical than other statements. def
statements, for example, can't be customized to produce something other than instances of function
, and it's far harder to create a function
object by calling types.FunctionType
explicitly.
CodePudding user response:
Yes I've looked this, but it doesn't provide something about principle of keyword argument in class inheritance, I am still confused
metaclass=...
is not about inheritance.
Everything in Python is an object. So when you define a class MyClass
, not only is MyClass()
an object but the class MyClass
itself is an object.
MyClass()
is an instance of MyClass
, simple enough.
But if MyClass
is also an object, what class is it an instance of?
If you do nothing, the object (!) MyClass
is an instance of the class type
.
If you do class MyClass(metaclass=Metaclass)
then MyClass
is an instance of Metaclass
.
Consider
class Metaclass(type):
pass
class MyClass1:
pass
class MyClass2(metaclass=Metaclass):
pass
Both MyClass1
and MyClass2
inherit from object
and only object
.
>>> MyClass1.__mro__
(<class '__main__.MyClass1'>, <class 'object'>)
>>> MyClass2.__mro__
(<class '__main__.MyClass2'>, <class 'object'>)
But their types differ:
>>> type(MyClass1)
<class 'type'>
>>> type(MyClass2)
<class '__main__.Metaclass'>
When would you need this? Usually, you don't. And when you do, you do the kind of metaprogramming where you already know the why and how.