Python Meta Classes (original) (raw)

A metaclass is a class that defines how other classes are created and behave. Just like objects are created from classes, classes themselves are created from metaclasses. In short:

By default, Python uses the built-in metaclass "type" to create all classes.

Steps to Create a Metaclass

  1. **Define a metaclass: Create a class that inherits from type. Optionally, define __new__ or __init__ to customize class creation.
  2. **Use the metaclass in a class: Specify metaclass=YourMeta when defining a class.
  3. **Class is created by the metaclass: The metaclass can modify attributes or methods of the class automatically.
  4. **Create instances of the class: Instances work normally, the metaclass only affects the class itself. Python `

class Meta(type): def new(cls, name, bases, dct): dct['greet'] = lambda self: f"Hello from {name}!" return super().new(cls, name, bases, dct)

class Person(metaclass=Meta): def init(self, name): self.name = name

p = Person("Olivia")

print(p.greet())

`

**Explanation:

Creating Subclass

Subclasses can also be created dynamically using type.

Python `

def init(self, ftype): self.ftype = ftype

def getFtype(self): return self.ftype

FoodType = type('FoodType', (object,), { 'init': init, 'getFtype': getFtype })

def vegFoods(self): return {'Spinach', 'Bitter Guard'}

VegType = type('VegType', (FoodType,), { 'vegFoods': vegFoods })

v = VegType("Vegetarian") print(v.getFtype()) print(v.vegFoods())

`

Output

Vegetarian {'Bitter Guard', 'Spinach'}

**Explanation:

Metaclasses can be inherited just like normal classes. When a class inherits from a metaclass, it becomes an instance of that metaclass.

Python `

class MetaCls(type): pass

A = MetaCls('A', (object,), {}) class B(object): pass class C(A, B): pass

print(type(A))
print(type(B))
print(type(C))

`

Output

<class '__main__.MetaCls'> <class 'type'> <class '__main__.MetaCls'>

**Explanation:

A class cannot inherit from two different metaclasses. Python will raise a TypeError.

Python `

class MetaCls(type): pass

Create class A using MetaCls

A = MetaCls('A', (object,), {}) print("Type of A:", type(A))

class DiffMetaCls(type): pass

Create class B using DiffMetaCls

B = DiffMetaCls('B', (object,), {}) print("Type of B:", type(B))

class C(A, B): pass

print("Type of C:", type(C))

`

Error:

TypeError: metaclass conflict: the metaclass of a derived class must be a (non-strict) subclass of the metaclasses of all its bases

**Explanation:

Metaclasses are useful when you want to control class creation or enforce rules.

**1. Class Verification: This example shows how a metaclass can enforce rules on class attributes.

Python `

class MainClass(type): def new(cls, name, bases, attrs): if 'foo' in attrs and 'bar' in attrs: raise TypeError(f"Class {name} cannot have both foo and bar") return super().new(cls, name, bases, attrs)

This will raise an error

class SubClass(metaclass=MainClass): foo = 42 bar = 34

`

**Explanation:

**2. Prevent Subclass Inheritance: This example shows how a metaclass can treat abstract classes differently, preventing certain checks for them while enforcing rules on normal classes.

Python `

class MetaCls(type): def new(cls, name, bases, attrs): if attrs.pop('abstract', False): print('Abstract Class:', name) return super().new(cls, name, bases, attrs) print('Normal Class:', name) return super().new(cls, name, bases, attrs)

class AbsCls(metaclass=MetaCls): abstract = True

class NormCls(metaclass=MetaCls): foo = 42

`

Output

Abstract Class: AbsCls Normal Class: NormCls

**Explanation:

Dynamic Generation of Classes

Dynamic class generation allows you to create classes at runtime instead of defining them statically in code.

Python `

class FoodType: events = []

def __init__(self, ftype, items):
    self.ftype = ftype
    self.items = items
    FoodType.events.append(self)

def run(self):
    print("Food Type:", self.ftype)
    print("Food Menu:", self.items)

@staticmethod
def run_events():
    for e in FoodType.events:
        e.run()

def sub_food(ftype): class_name = ftype.capitalize() def init(self, items): FoodType.init(self, ftype, items) globals()[class_name] = type(class_name, (FoodType,), {'init': init})

Create dynamic classes

[ sub_food(ftype) for ftype in ["Vegetarian", "Nonvegetarian"] ]

Vegetarian(['Spinach', 'Bitter Guard']) Nonvegetarian(['Meat', 'Fish']) FoodType.run_events()

`