Meta-Classes In Python
Published: 2021-04-29 14:31:31


__** Meta-classes :__

The term metaprogramming refers to the potential for a program to have knowledge of or manipulate itself. Python supports a form of metaprogramming for classes called meta-classes. Meta-classes are an esoteric OOP concept, lurking behind virtually all Python code.

__** Old-Style Vs New-Style Classes :__

In the Python, a class can be one of two varieties.

__(1) Old-Style Classes :-__ 

With old-style classes, class and type are not quite the same thing. An instance of an old-style class is always implemented from a single built-in type called instance. If obj is an instance of an old-style class, obj.class designates the class, but type(obj) is always instance.

    >>> class Foo:
    ...     pass
    ...
    >>> x = Foo()
    >>> x.class
    <class main.Foo at 0x000000000535CC48>
    >>> type(x)
    <type 'instance'>

__(2) New-Style Classes :-__

New-style classes unify the concepts of class and type. If obj is an instance of a new-style class, type(obj) is the same as obj.class

      >>> class Foo:
      ...     pass
      >>> obj = Foo()
      >>> obj.__class__
      <class '__main__.Foo'>
      >>> type(obj)
      <class '__main__.Foo'>
      >>> obj.__class__ is type(obj)
       True

__** Type And Class :__ 

In Python, everything is an object. Classes are objects as well. As a result, a class must have a type. What is the type of a class?
Consider the following

     >>> class Foo:
     ...     pass
     ...
     >>> x = Foo()

     >>> type(x)
     <class 'main.Foo'>

     >>> type(Foo)
     <class 'type'> 

The type of x is class Foo. But the type of Foo, the class itself, is type. In general, the type of any new-style class is type. The type of the built-in classes you are familiar with is also type.

     >>> for t in int, float, dict, list, tuple:
     ...     print(type(t))
     ...
     <class 'type'>
     <class 'type'>
     <class 'type'>
     <class 'type'>
     <class 'type'>

For that matter, the type of type is type as well.

     >>> type(type)
     <class 'type'>

Type is a meta-class, of which classes are instances. Just as an ordinary object is an instance of a class, any new-style class in Python, and thus any class in Python 3, is an instance of the type meta-class.

In the above case:

(a) x is an instance of class Foo.
(b) Foo is an instance of the type meta-class.
(c) type is also an instance of the type meta-class, so it is an 
    instance of itself.

__** Defining A Class Dynamically :__

The built-in type() function, when passed one argument, returns the type of an object.  For new-style classes, that is generally the same as the object’s class attribute:

     >>> type(3)
     <class 'int'>

     >>> type(['foo', 'bar', 'baz'])
     <class 'list'>

     >>> t = (1, 2, 3, 4, 5)
     >>> type(t)
     <class 'tuple'>

     >>> class Foo:
     ...     pass
     ...
     >>> type(Foo())
     <class '__main__.Foo'>

You can also call type() with three arguments—type(< name >, < bases >, < dct >):

(1)  <name> specifies the class name. This becomes the __name__ 
     attribute of the class.

(2)  <bases> specifies a tuple of the base classes from which the 
     class inherits. This becomes the __bases__ attribute of the 
     class.

(3)  <dct> specifies a namespace dictionary containing 
     definitions for the class body. This becomes the __dict__ 
     attribute of the class.

Calling type() in this manner creates a new instance of the type meta-class. In other words, it dynamically creates a new class.

__** Is This Really Necessary :__

It is the essence of how meta-classes work. They allow customization of class instantiation.