Search code examples
pythonclassinheritancemetaclasspython-class

Keyword arguments in python class inheritance


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!


Solution

  • 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.