Upon doing
class A(object):
__metaclass__ = MyMeta
Consider:
def class_pre_decorator(name, bases, namespace):
# do something with namespace
return type(name, bases, namespace)
There is no way in Python 3 to guess the callable actually used to instantiate a class if it gives no other hint (like setting an attribute on the class) that it was used:
# python 2
class A(object):
__metaclass__ = class_pre_decorator
and
# Python 3 class A(metaclass = class_pre_decorator): pass
Last Updated : 18 Aug, 2020
Vegetarian
Vegetarian {
'Spinach',
'Bitter Guard'
}
clsname: C
superclasses: (<class 'object'>, )
attrdict: {}
class type: <class '__main__.MetaCls'>
<class 'type'>
<class '__main__.MetaCls'>
The class Instance is the class used for all instances of classes built using the Tracing metaclass, e.g. aninstance. It has two methods: ,The __init__ method is invoked when a new Tracing instance is created, e.g. the definition of class MyTracedClass later in the example. It simply saves the class name, base classes and namespace as instance variables. ,The __call__ method is invoked when a Tracing instance is called, e.g. the creation of aninstance later in the example. It returns an instance of the class Instance, which is defined next. ,The __init__ method is invoked from the Tracing.__call__ method above to initialize a new instance. It saves the class reference as an instance variable. It uses a funny name because the user's instance variables (e.g. self.a later in the example) live in the same namespace.
Note the two indirection levels. Take a simple example:
class B:
pass
class C(B):
pass
Still confused? Here's a simple device due to Don himself to explain metaclasses. Take a simple class definition; assume B is a special class that triggers Don's hook:
class C(B):
a = 1
b = 2
class C(B): a = 1 b = 2
C = type(B)('C', (B, ), {
'a': 1,
'b': 2
})
Note that the contents of the namespace dictionary is simply whatever names were defined in the class statement. A little-known fact is that when Python executes a class statement, it enters a new local namespace, and all assignments and function definitions take place in this namespace. Thus, after executing the following class statement:
class C:
a = 1
def f(s): pass
Let's repeat our simple example from above:
class C(B):
a = 1
b = 2
class Color(Enum):
red = 1
green = 2
blue = 3
print Color.red
The dir function's output shows that the Human class has lots of methods and attributes, most of which are available to the Human class from the object base class. Python provides a __bases__ attribute on each class that can be used to obtain a list of classes the given class inherits.,The above output shows that the Human class has object as a base class. We can also look at the attributes and methods defined by the object class using the dir function.,The dir function returns a list of all the attributes and methods defined on any Python object.,The output of the above code shows that human_obj is an instance of class Human with the first_name as Virat and the last_name as Kohli. If we look at the above code closely, it's natural to have some questions:
class Human:
pass
dir(Human)
# Output: ['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__',
'__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__',
'__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__',
'__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__'
]
print(Human.__bases__)
# Output: (<class 'object'>,)
dir(object)
# Output: ['__class__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__',
'__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__',
'__lt__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__',
'__sizeof__', '__str__', '__subclasshook__'
]
class Human(object):
pass
# A simple integer data type
a = 9
# The type of a is int (i.e., a is an object of class int)
type(a) # Output: <class 'int'>
# The type of b is float (i.e., b is an object of the class float)
b = 9.0
type(b) # Output: <class 'float'>
In Python, a metaclass is a “class of a class”. It defines how a class itself is constructed.,This type class is an example of a metaclass in Python.,Metaclasses are the objects that create classes. You can think of a metaclass as being a “class of a class”.,A metaclass is a “class of a class” in Python. It acts as a class factory. Whenever you use the keyword class, a metaclass creates a class object for your class definition behind the scenes.
For instance:
class Fruit:
pass
Let’s demonstrate each of these with a Fruit class:
# Define a class
class Fruit:
pass
# Assign the class object into a variable
c = Fruit
print(c)
# Add attributes to the class
Fruit.age = 0
print(Fruit.age)
# Pass the class object as an argument
def display(class_obj):
print(class_obj)
display(Fruit)
# Copy the class object
import copy
Fruit2 = copy.deepcopy(Fruit)
print(Fruit2)
This code—believe it or not— runs successfully. Here is what it prints into the console:
<class '__main__.Fruit'>
0
<class '__main__.Fruit'>
<class '__main__.Fruit'>
Output:
<class '__main__.give.<locals>.Something'>
To define a class using the type class, use the following syntax:
type(name, bases, attrs)
Every class created in Python has an underlying Metaclass. So when you’re creating a class, you are indirectly using the Metaclass. It happens implicitly, you don’t need to specify anything.,Now that you know Metaclass creates all the other classes in Python and defines their behavior using type class. But then you must be wondering, is there any other way we can create Metaclass? So, let’s see how to create a custom Metaclass that. ,Now that you understand everything in Python has a type associated with it. In the next topic, we will try to understand how Metaclass actually works.,After Python executes all the dictionary in a namespace, it invokes type object which creates objects of a class. There are two methods that we can use to create custom Metaclass.
The class of an object can be checked by using the __class__ attribute. Let’s see this simple example:
class Demo:
pass
#This is a class named demo
test = Demo()
print(test.__class__) #shows class of obj
print(type(test)) #alternate method
Languages like Java or C++ have data types like float, char, int, etc. whereas Python treats each variable as an object. And each object belongs to a class like an int class or str class. You can simply check the class of any variable using a built-in function called type().
number = 10993
print("Type associated is:", type(number))
name = "Aishwarya"
print("Type associated is:", type(name))
Python has a built-in Metaclass called type. Unlike Java or C, where there are primary data types. Every variable or object in Python has a class associated with it. Python use Type class behind-the-scenes to create all the classes. In the previous topic, we saw how we can check the class of an object by using type(). Let’s take an example of how we can define a new type, by creating a simple class.
class Edureka():
obj = Edureka()
print(type(obj))
When we pass parameters through type class, it uses the following syntax.
type(__name__, __base__, attributes)
class EduFirst(type):
def __new__(cls, name, base_cls, dict):
pass
class EduSecond(type):
def __init__(self, name, base_cls, dict):
pass
First, define a Prop class that accepts an attribute name and contains three methods for creating a property object(set, get, and delete). The Data metaclass will use this Prop class for adding property objects to the class.,Second, create a new static method define_property() that creates a property object for each attribute from the props list:,First, define a function decorator that returns a new class which is an instance of the Data metaclass:,The following defines the repr static method that returns a function and uses it for the __repr__ attribute of the class object:
The following defines a Person
class with two attributes name
and age
:
.wp - block - code {
border: 0;
padding: 0;
}
.wp - block - code > div {
overflow: auto;
}
.shcb - language {
border: 0;
clip: rect(1 px, 1 px, 1 px, 1 px); -
webkit - clip - path: inset(50 % );
clip - path: inset(50 % );
height: 1 px;
margin: -1 px;
overflow: hidden;
padding: 0;
position: absolute;
width: 1 px;
word - wrap: normal;
word - break: normal;
}
.hljs {
box - sizing: border - box;
}
.hljs.shcb - code - table {
display: table;
width: 100 % ;
}
.hljs.shcb - code - table > .shcb - loc {
color: inherit;
display: table - row;
width: 100 % ;
}
.hljs.shcb - code - table.shcb - loc > span {
display: table - cell;
}
.wp - block - code code.hljs: not(.shcb - wrap - lines) {
white - space: pre;
}
.wp - block - code code.hljs.shcb - wrap - lines {
white - space: pre - wrap;
}
.hljs.shcb - line - numbers {
border - spacing: 0;
counter - reset: line;
}
.hljs.shcb - line - numbers > .shcb - loc {
counter - increment: line;
}
.hljs.shcb - line - numbers.shcb - loc > span {
padding - left: 0.75 em;
}
.hljs.shcb - line - numbers.shcb - loc::before {
border - right: 1 px solid #ddd;
content: counter(line);
display: table - cell;
padding: 0 0.75 em;
text - align: right; -
webkit - user - select: none; -
moz - user - select: none; -
ms - user - select: none;
user - select: none;
white - space: nowrap;
width: 1 % ;
}
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
@property
def name(self):
return self._name
@name.setter
def name(self, value):
self._name = value
@property
def age(self):
return self._age
@age.setter
def age(self, value):
self._age = value
def __eq__(self, other):
return self.name == other.name and self.age == other.age
def __hash__(self):
return hash(f '{self.name, self.age}')
def __str__(self):
return f 'Person(name={self.name},age={self.age})'
def __repr__(self):
return f 'Person(name={self.name},age={self.age})'
Code language: Python(python)
Imagine you want to define a Person class like this and automagically has all the functions above:
class Person:
props = ['first_name', 'last_name', 'age'] Code language: Python(python)
First, define the Data
metaclass that inherits from the type
class:
class Data(type):
passCode language: Python(python)
First, define a Prop
class that accepts an attribute name and contains three methods for creating a property object(set
, get
, and delete
). The Data
metaclass will use this Prop
class for adding property objects to the class.
class Prop:
def __init__(self, attr):
self._attr = attr
def get(self, obj):
return getattr(obj, self._attr)
def set(self, obj, value):
return setattr(obj, self._attr, value)
def delete(self, obj):
return delattr(obj, self._attr) Code language: Python(python)
Second, create a new static method define_property()
that creates a property object for each attribute from the props
list:
class Data(type):
def __new__(mcs, name, bases, class_dict):
class_obj = super().__new__(mcs, name, bases, class_dict)
Data.define_property(class_obj)
return class_obj
@staticmethod
def define_property(class_obj):
for prop in class_obj.props:
attr = f '_{prop}'
prop_obj = property(
fget = Prop(attr).get,
fset = Prop(attr).set,
fdel = Prop(attr).delete
)
setattr(class_obj, prop, prop_obj)
return class_objCode language: Python(python)