Home > Software engineering >  Keyword arguments in python class inheritance
Keyword arguments in python class inheritance

Time:02-11

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.

  • Related