# 182. Metaclasses

**Snippet 1: Basic Metaclass Example**

```python
class MyMeta(type):
    def __new__(cls, name, bases, dct):
        print(f"Creating class {name}")
        return super().__new__(cls, name, bases, dct)

class MyClass(metaclass=MyMeta):
    pass

# Output: Creating class MyClass
```

***

**Snippet 2: Adding Custom Attributes to Classes**

```python
class AttributeAddingMeta(type):
    def __new__(cls, name, bases, dct):
        dct['custom_attribute'] = "Hello from metaclass"
        return super().__new__(cls, name, bases, dct)

class MyClass(metaclass=AttributeAddingMeta):
    pass

print(MyClass.custom_attribute)  # Output: Hello from metaclass
```

***

**Snippet 3: Validating Class Attributes**

```python
class ValidatorMeta(type):
    def __new__(cls, name, bases, dct):
        if 'required_attribute' not in dct:
            raise TypeError(f"Class {name} must have a 'required_attribute'")
        return super().__new__(cls, name, bases, dct)

class ValidClass(metaclass=ValidatorMeta):
    required_attribute = 42

# class InvalidClass(metaclass=ValidatorMeta):  # Raises TypeError
#     pass
```

***

**Snippet 4: Modifying Methods in a Class**

```python
class MethodModifierMeta(type):
    def __new__(cls, name, bases, dct):
        if 'say_hello' in dct:
            original_method = dct['say_hello']

            def new_method(self):
                print("Modified behavior")
                original_method(self)

            dct['say_hello'] = new_method
        return super().__new__(cls, name, bases, dct)

class MyClass(metaclass=MethodModifierMeta):
    def say_hello(self):
        print("Original behavior")

obj = MyClass()
obj.say_hello()
# Output:
# Modified behavior
# Original behavior
```

***

**Snippet 5: Enforcing Singleton Pattern**

```python
class SingletonMeta(type):
    _instances = {}

    def __call__(cls, *args, **kwargs):
        if cls not in cls._instances:
            cls._instances[cls] = super().__call__(*args, **kwargs)
        return cls._instances[cls]

class SingletonClass(metaclass=SingletonMeta):
    pass

a = SingletonClass()
b = SingletonClass()
print(a is b)  # Output: True
```

***

**Snippet 6: Dynamically Creating Classes**

```python
MyDynamicClass = type('MyDynamicClass', (object,), {'greet': lambda self: "Hello, Dynamic!"})

obj = MyDynamicClass()
print(obj.greet())  # Output: Hello, Dynamic!
```

***

**Snippet 7: Customizing Class Instantiation**

```python
class CustomInitMeta(type):
    def __call__(cls, *args, **kwargs):
        print("Custom initialization logic")
        instance = super().__call__(*args, **kwargs)
        return instance

class MyClass(metaclass=CustomInitMeta):
    def __init__(self):
        print("Normal __init__")

obj = MyClass()
# Output:
# Custom initialization logic
# Normal __init__
```

***

**Snippet 8: Preventing Class Inheritance**

```python
class NoInheritanceMeta(type):
    def __new__(cls, name, bases, dct):
        for base in bases:
            if isinstance(base, NoInheritanceMeta):
                raise TypeError(f"Class {name} cannot inherit from {base.__name__}")
        return super().__new__(cls, name, bases, dct)

class BaseClass(metaclass=NoInheritanceMeta):
    pass

# class DerivedClass(BaseClass):  # Raises TypeError
#     pass
```

***

**Snippet 9: Adding Class Methods Automatically**

```python
class AutoClassMethodMeta(type):
    def __new__(cls, name, bases, dct):
        dct['auto_method'] = lambda cls: f"Hello from {cls.__name__}"
        return super().__new__(cls, name, bases, dct)

class MyClass(metaclass=AutoClassMethodMeta):
    pass

print(MyClass.auto_method())  # Output: Hello from MyClass
```

***

**Snippet 10: Counting Class Instances**

```python
class InstanceCounterMeta(type):
    def __new__(cls, name, bases, dct):
        dct['_instance_count'] = 0
        return super().__new__(cls, name, bases, dct)

    def __call__(cls, *args, **kwargs):
        cls._instance_count += 1
        return super().__call__(*args, **kwargs)

class MyClass(metaclass=InstanceCounterMeta):
    pass

a = MyClass()
b = MyClass()
print(MyClass._instance_count)  # Output: 2
```

***
